繁体   English   中英

从pycharm中的重组文本文件中删除面包屑

[英]Removing breadcrumbs from restructured text files in pycharm

我大约需要删除13,000个文件。 每个文件开头的模式大致如下:

Title
=====

| |image0| `link <link1.html>`__ |image1| ::
  `link2 <link2.html>`__ ::
  `link3 <link3.html>`__
| **Introduced** : VersionXXX

但是,在某些文件中,标题行和最后一行之间的部分是2或4,具体取决于树的深度。 无论标题行和此处显示的最后一行之间有多行,我都希望将中间部分完全删除。 我不太清楚如何做到这一点,不胜感激。 我正在使用pycharm,并且它们有一个正则表达式工具(到目前为止还没有成功),但我同样很高兴使用sed或python等替代文件来遍历文件。

预期结果:

Title
=====

| **Introduced** : VersionXXX

感谢所有出色的解决方案。 避免写入单独文件的最终解决方案

import os

src_dir = '/PycharmProjects/docs/testfiles'
logf = open('failed_file_log.txt', 'w')

for filename in os.listdir(src_dir):
    print(filename)

    with open('{}/{}'.format(src_dir, filename), 'r') as f:
        lines = f.readlines()
    with open('{}/{}'.format(src_dir, filename), 'w') as f:
        try:
            for i in range(3):
                f.write(lines[i])
            copy = False
            for line in lines:
                if copy:
                    f.write(line)
                elif line.startswith('| **Introduced**'):
                    copy = True
                    f.write(line)
        except Exception as e:
            logf.write('Failed to rewrite {}'.format(filename))
        finally:
            pass

正如sed在OP中标记的问题一样,以下是获得所需结果的两种方法:

sed -n  '/Title/{N;N;p}; /Introduced/{p}' input
Title
=====

| **Introduced** : VersionXXX

要么

awk

awk '/Title/{print;getline;print;getline;print}/Introduced/{print}' input
Title
=====

| **Introduced** : VersionXXX

由于您正在寻找大多数固定模式,因此我将使用不带正则表达式的Python复制文件。 该过程非常简单:复制前三行,然后跳过所有内容,直到到达| **Introduced** | **Introduced** ,然后将其余内容复制过来。

with open('myfile.rst') as fin, open('myfile_out.rst') as fout:
    for _ in range(3):
        fout.write(next(fin))
    copy = False
    for line in fin:
        if copy:
            fout.write(line)
        elif line.startswith('| **Introduced**'):
            copy = True
            fout.write(line)

将此练习应用于文件层次结构,并将输出移回输入名称,这是读者的一项练习。

您可以使用2个捕获组,并通过使用重复模式来匹配介于两者之间的内容,该模式使用负前瞻(?!

然后在替换中使用这两个组,在python中使用re.sub ,替换将是r'\\1\\2'

(\bTitle\n=+\n)(?:\n(?!\| \*\*).*)*(\n\| \*\*Introduced\*\* : Version.*)

说明

  • (\\bTitle\\n=+\\n)捕获组1,匹配标题,换行符,a +和换行符1+次
  • (?:非捕获组
    • \\n(?!\\| \\*\\*).*匹配换行符并断言直接在右边的不是| ** | **使用负前瞻。 然后匹配0+次除换行符以外的任何字符
  • )*关闭非捕获组并重复0次以上
  • (\\n\\| \\*\\*Introduced\\*\\* : Version.*)捕获组2,匹配换行符和匹配最后一行的模式

正则表达式演示

此表达式使用三个捕获组,而我们不想要的部分在第二个中,我们可以简单地替换它( $1$3 )。

(.+\s*=====\s*)([\s\S]*)(\|\s+\*\*Introduced\*\* : .+)

演示

测试

# coding=utf8
# the above tag defines encoding for this document and is for Python 2.x compatibility

import re

regex = r"(.+\s*=====\s*)([\s\S]*)(\|\s+\*\*Introduced\*\* : .+)"

test_str = ("Title\n"
    "=====\n\n"
    "| |image0| `link <link1.html>`__ |image1| ::\n"
    "  `link2 <link2.html>`__ ::\n"
    "  `link3 <link3.html>`__\n"
    "| **Introduced** : VersionXXX")

subst = "\\1\\3"

# You can manually specify the number of replacements by changing the 4th argument
result = re.sub(regex, subst, test_str, 0, re.MULTILINE)

if result:
    print (result)

# Note: for Python 2.7 compatibility, use ur"" to prefix the regex and u"" to prefix the test string and substitution.

sed有其用途,但需要疯狂的技能才能按需进行多行处理。 这是久经考验的* nix文本处理语言awk的替代方法;-)

**cleanup.awk**
#!/bin/awk -f
{
  # print "dbg:$0="$0
}
/^$/{
  print $0
  inside_unneeded=1;
}
{
  if ($0 ~ /^\| \*\*Introduced\*\*/) {
    print $0
    inside_unneeded=0
  }
  else if (! inside_unneeded) {
    print $0
  }

你需要

chmod 755 cleanup.awk

并运行为

cleanup.awk file > file.new && /bin/rm file

如果您有能力保留备份(推荐),请执行&& mv file file.sav && mv file.new file 或者,您可以重定向到另一个目录,然后不必处理任何&&处理,即。 cleanup.awk file > /alt/path/for/new/data/file

将产生输出

Title
=====

| **Introduced** : VersionXXX

有可能使用awk速记逻辑来大大减少此脚本的大小的方法,但对于熟悉if/else if/else类型逻辑的一般公众,我将其保持在可解码的状态。

所有块( { ... }之间的代码都针对输入的每一行执行,而以/^$/开头的块仅针对空行进行处理。如果这些空行上有空格,则需要/^[ <tab>]*$/{代替(不要键入<tab> ,从键盘上插入一个普通的tab )。

IHTH。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM