【问题标题】:Remove numbered chapter titles that do not have text immediately below删除下面没有文字的编号章节标题
【发布时间】:2021-06-07 00:09:54
【问题描述】:

我有 3000 到 5000 行的文本文件列表,我将其称为编号章节标题。我想删除标题正下方没有文字(句子)的行。

喜欢:

Chapter 1
Chapter 2
Chapter 3
Hello world
Chapter 4
Chapter 5
I love you. 
Chapter 6
how many times do I have to do this
chapter 7
Chapter 8
Chapter 9
Some lines have some numbers, numbers and text.
some chapter text has multiple lines.
I thought the best method is to
look for a chapter header line 
that has a chapter header line 
immediately below it.  The last chapter 
line becomes an issue if it does 
not have any text.
Chapter 10

我想删除第 1、2、4、7、8 和 10 章的行

如果以下行也是使用正向前瞻的章节行,我尝试与 grep 和 sed 匹配章节行(前瞻不会被删除)

grep -Pz '(?s)Chapter\s[\d]{4}\n(?=(Chapter\s[\d]{4}\n)) filename.txt

或在 sed 中(我不理解带有 sed 的脚本)...

sed 's/(?s)Chapter\s[\d]{4}\n(?=(Chapter\s[\d]{4}\n))/ /g' filename.txt

Grep 不能很好地处理多行(如果你使用 -Pz 标签,一切都变成一行。如果一切都是一行,那么任何匹配的任何地方都意味着该行是匹配的。

我也尝试过使用 sed 进行预读,所以我不能使用预读,因为匹配的一行的一部分。

我知道我可以使用 python 或其他脚本语言来做到这一点,但与 bash 命令相比它太慢了。与 python 相比,我能够非常快速地从更大的混乱处理到这个级别,所以我希望我可以只使用 bash 命令来完成这最后一步,并使我们的更新窗口更短。这些文件很大,在有文本的章节中有更多的随机文本。可以是多个句子。

干杯,感谢您的帮助!

【问题讨论】:

    标签: regex shell sed grep


    【解决方案1】:

    使用sed

    sed -e '
    /^[Cc]hapter [0-9]/!b
    :Z
    $d
    N
    /\n[Cc]hapter [0-9]/{D;bZ;}
    ' -- data
    

    匹配时打开一个 2 行窗口,将 (N) 下一行附加到当前行。 如果两个连续匹配删除 (D) 第一个并继续。一种 最后一行的匹配被删除 ($d)。

    【讨论】:

      【解决方案2】:

      如果perl 是您的选择,请尝试一下:

      perl -0777 -pe 's/Chapter\s*\d+\n(?=Chapter\s*\d+\n)|Chapter\s*\d+\n?$//ig' filename.txt > newfile.txt
      

      我生成了一个包含约 5,000 行的文件进行测试。然后上面的脚本在几毫秒内完成。

      解释:

      • -0777 选项告诉perl 一次吞下所有行以处理跨行的输入。
      • 正则表达式Chapter\s*\d+\n(?=Chapter\s*\d+\n)|Chapter\s*\d+\n?$ 匹配紧跟另一章行或文件结尾的章节行。

      【讨论】:

      • 如果我将列表作为 grep 或 cat 的 std 输入推入,我认为我可以省略 -0777,对吗?
      • 不。 perl 的默认 (w/o -0777) 行为是将输入逐行处理为grepsedawk,即使您通过管道将文件输入perl 的标准输入.
      • 花了几分钟,因为我没有意识到每段末尾都有一个 \r\n (我假设只是 \n (当然不是你的错))。谢谢一堆。除了最后一行之外,它可以工作 - 如果最后一个章节标题之后没有文本,则最后一个章节标题仍然存在。我可以研究其他选项。主要工作已经完成——而且速度非常快。干得好。
      • 感谢您的反馈。我打算考虑最后一行是没有文本的章节标题的情况(如您的示例中的Chapter 10)。可能的问题是您的文件在文件末尾没有行尾代码。当然这不是你的错,而是 Windows 文本编辑器的麻烦行为。我已经相应地修复了我的脚本。如果您对接受的答案感到满意,那没关系。但如果您有时间测试我更新的脚本,我会很高兴。 BR。
      【解决方案3】:

      这是 awk/gawk 做得很好的一个 - 而对于 awk 这个是很快的。

      算法 - 您可以记住上一行,或者,转储上一行和当前行,或者只是当前行(取决于之前发生的事情)。很啰嗦,但写起来很快。

      awk '
      BEGIN { last=""; }
      /^[Cc]hapter *[0-9][0-9]* *$/ {
        last=$0;
        next;
      }
      /.*/ {
        if (last) {
          print last;
          last="";
        }
        print $0;
        next;
      }' IP.txt
      

      通常您还需要一个 END 块 - 但在这种情况下,如果设置了 last 则无关紧要。

      【讨论】:

      • 也可以完美运行。谢谢!我只是无法理解脚本的工作原理。这是想要的结果(去掉了最后一章的标题) 第 3 章 Hello world 第 5 章我爱你。第 6 章我必须这样做多少次第 9 章有些行有一些数字、数字和文本。某些章节文本有多行。我认为最好的方法是寻找一个章节标题行,它下面有一个章节标题行。如果最后一章行没有任何文字,则会成为问题。
      • 您有两种类型的行被处理 - 章节标题或其他任何内容。我们使用 last 变量来构建一个简单的状态机......如果定义了 last 你在前一行有一个章节标题 - 所以如果你得到另一个章节标题 - 你可以忽略最后一个(为下一个设置通过记住最后一个标题行)...如果您得到任何其他内容但有最后一个设置 - 那么您必须保留一个章节标题 - 所以打印它,然后打印当前处理的行,然后我们回到开始状态。
      猜你喜欢
      • 2021-08-26
      • 1970-01-01
      • 2020-09-25
      • 2012-11-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-11-25
      相关资源
      最近更新 更多