【问题标题】:Using pcregrep to grep multiple lines使用 pcregrep grep 多行
【发布时间】:2019-09-13 19:10:41
【问题描述】:

我有一个具有以下模式的文件。

Foo $var1
.........
.........

Foo $var2 
..........
..........
..........
Yes

我只想匹配以“Foo”开头并具有“是”的“部分”。 (您会注意到每个部分的末尾都有一个空的换行符)

预期的输出应该是。

Foo $var2 
..........
..........
..........
Yes

我试过了

pcregrep -M "^Foo(.|\n)*^是"

但不幸的是,这从上一节开始匹配,并将倒数第二节与返回匹配项为“是”的部分混为一谈,所以我没有得到一个以“Foo”开头并具有“是的”,但以“Foo”开头的部分与以前一样多

我的困境是,如果在本节末尾我匹配“Foo”却看不到“Yes”,如何丢弃上一个匹配项。

我尝试使用后视功能,但它不能用于可变长度。

【问题讨论】:

  • 请将该示例输入的所需输出(无描述)添加到您的问题(无评论)。

标签: regex grep pcregrep


【解决方案1】:

您可以从字符串的开头使用 match Foo,然后匹配所有不以 Yes 或 Foo 开头的行。

如果 Foo 和 Yes 不应该是更大单词的一部分,您可以使用单词边界 \b

^Foo\b.*(?:\n(?!Yes\b|Foo\b).*)*\nYes\b

部分

  • ^ 字符串开始
  • Foo\b.* 匹配 Foo 后跟 0+ 次除换行符以外的任何字符
  • (?:非捕获组
    • \n匹配换行符
    • (?!Yes\b|Foo\b) Negative lookahead, assert not Yes or Foo 直接在右边
    • .* 匹配除换行符以外的任何字符 0+ 次
  • )*关闭组并重复0+次
  • \nYes\b

Regex demo

例如

pcregrep -Mo '^Foo\b.*(?:\n(?!Yes\b|Foo\b).*)*\nYes\b' file

输出

Foo $var2
..........
..........
..........
Yes

【讨论】:

  • 这行得通。但我必须充实这个词的边界。最后将其简化为 pcregrep -Mo '^Foo.*(?:\n(?!Foo).*)*\nYes'.
【解决方案2】:

如果你可以改用gnu awk,你可以让awk像这样在块模式下工作:

awk -v RS='Foo' -v ORS='' '/Yes/ {print RS$0}' file
Foo $var2
..........
..........
..........
Yes

【讨论】:

    【解决方案3】:

    如果您使用的是启用 PCRE 的 grep,则会得到类似这样的结果
    只是那些带有 YES

    Foo

    请注意,我不确定 grep 是否会跨行。
    可能,但我个人不知道。

    (?m)^Foo\K(?:(?!^Foo)[\S\s])+(?=^Yes)

    https://regex101.com/r/HCrcGO/1

    展开

     (?m)
     ^ Foo
     \K 
     (?:
          (?! ^ Foo )
          [\S\s] 
     )+
     (?= ^ Yes )
    

    【讨论】:

    • 如何使该模式适应 pcregrep?
    • @henrychiedozie - 我不确定,除了它在 PCRE 下工作。也许只是试一试?
    • 它不起作用。它显示了这个错误。 pcregrep:偏移量 11 处的命令行正则表达式出错:(? 或 (?-
    • 但我想让它发挥作用的方法是将积极的前瞻和消极的前瞻结合起来。但让它发挥作用的模式是我仍在试图弄清楚的。
    • @dochenaj - 这是关于整个 PCREGREP 事情的一些信息,祝你有美好的一天! pcre.org/original/doc/html/pcregrep.html 选项设置 - (?m) sets multiline matching. The settings of the PCRE_CASELESS, PCRE_MULTILINE, PCRE_DOTALL, and PCRE_EXTENDED options (which are Perl-compatible) can be changed from within the pattern by a sequence of Perl option letters enclosed between "(?" and ")" 匹配点重置 - \K Reset start of match
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-27
    • 1970-01-01
    • 2014-05-13
    • 1970-01-01
    • 2016-03-01
    相关资源
    最近更新 更多