【问题标题】:pcregrep or grep: searching with lookaheads not workingpcregrep 或 grep:使用前瞻搜索不起作用
【发布时间】:2020-02-24 05:25:12
【问题描述】:

我正在尝试使用前瞻搜索它在 pcregrep 或 grep 中不起作用的正则表达式

我想搜索片段

  • 可能跨越多行,
  • 以 PQXY 开头在一行的开头和
  • 以 OFEJ 结束在行的末尾和
  • 中间不包含 PQXY 或 OFEJ

一般我在 sublime text find 中使用以下内容并且效果很好

(?s)(^PQXY(?:(?!PQXY|OFEJ).)*OFEJ\n)

现在我想查找此类事件的计数,所以我尝试使用 grep 或 pcergrep,两者都不起作用。

pcregrep -c "(?s)(^PQXY(?:(?!PQXY|OFEJ).)*OFEJ\n)" file.txt
zsh: event not found: PQXY|OFEJ).)

和 grep

$ grep -c -zoP "(?s)(^PQXY(?:(?!PQXY|OFEJTRANS).)*OFEJTRANS\n)" CB_raw_testing_21_feb_CORRECTIONS_0002.txt
zsh: event not found: PQXY|OFEJTRANS).)

我该怎么做

根据@paxdiablo 和@anubha 回答。

主要错误是@paxdiablo 解决的单引号

$ pcregrep -c -M '(^PQXY(?:(?!PQXY|OFEJ).)*OFEJ\n)' file.txt 
0

正则表达式的解决方案是在@anubha 的基础上添加(?s)。当然\n 也可以代替(\R|\z)

$ pcregrep -c -M '(?s)(^PQXY(?:(?!PQXY|OFEJ).)*OFEJ\n)' file.txt
11726

【问题讨论】:

  • 如果文件不以换行符结尾,则仅供参考 \n 将不起作用。

标签: regex grep pcregrep


【解决方案1】:

使用gnu grep

grep -ozP '(?ms)^PQXY(?:(?!PQXY|OFEJ).)*OFEJ(\R|\z)' file
  • 您必须使用-z 选项将输入和输出数据视为行序列,每行以零字节结尾。

  • 确保在您的模式中使用单引号,以便 shell 的历史模块不会尝试处理 !

  • 添加了(?m) (MULTILINE) 修饰符以允许在每行的正则表达式中使用^$
  • 使用(\R|\z) 允许结束模式在文件末尾不带换行符而结束。 \R 匹配任何 ind 换行符,包括 unicode 字符,\z 匹配输入结尾。

Working Demo


pcregrep中的等效解决方案

pcregrep -M '(?s)^PQXY(?:(?!PQXY|OFEJ).)*OFEJ(\R|\z)' file

-Mpcregrep 中启用多行选项。

【讨论】:

  • 它解决了错误但显示错误的结果。 (?:(?!PQXY|OFEJ).) 不工作
  • @SanthoshYedidi:我添加了上述解决方案的工作演示ideone.com/lAKMJi
  • 是的,pcgrep 命令按照您的回答工作。我用对我有用的东西更新了这个问题。但是 grep 不起作用
  • 我正在检查一些示例文本
  • 既然你event not found的主要问​​题得到了回答,我建议你发布一个不同的问题来解决次要问题:)
【解决方案2】:

zsh: event not found: PQXY|OFEJ).)

由于这是zsh 引发错误,几乎肯定因为它试图处理双引号内的内容。为了保护它,您应该使用 引号,例如:

pcregrep -c '(?s)(^PQXY(?:(?!PQXY|OFEJ).)*OFEJ\n)' file.txt

我没有安装pcregrep,但这里有一个文字记录显示只有echo 的问题:

pax> echo "(?s)(^PQXY(?:(?!PQXY|OFEJ).)*OFEJ)"
zsh: event not found: PQXY|OFEJ).)

pax> echo '(?s)(^PQXY(?:(?OFEJ)'
(?s)(^PQXY(?:(?OFEJ)

在解决问题而不是使用特定的工具方面,我实际上会选择awk(a)案子。您可以执行以下操作:

awk '/^PQXY/     { s = $0; c = 1; next}
     /OFEJ$/     { if (c == 1) { print s""ORS""$0; c = 0 }; next }
     /OFEJ|PQXY/ { c = 0; next }
     c == 1      { s = s""ORS""$0 }' inputFile

这通过使用字符串和标志来控制收集和状态的行来工作,最初它们是空字符串和零。

然后,对于每一行:

  • 如果以 PQXY 开头,存储该行并设置收集标志,然后转到下一个输入行。
  • 否则,如果它以OFEJ结尾并且您正在收集,则输出收集的部分并停止收集,然后转到下一个输入行。
  • 否则,如果其中有任何一个字符串,则停止收集,移至下一个输入行。
  • 否则,如果正在收集,则追加当前行并(隐式)移动到下一个输入行。

我用一些有限的测试数据对此进行了测试,它似乎工作正常。这是我用于测试的bash 脚本(b),您可以根据需要添加尽可能多的测试用例,以解决您的问题。

for i in \
    "PQXY 1\nabc\n2 OFEJ\n" \
    "PQXY 1\nabc\n2 OFEJx\n" \
    "PQXY 1\nabc\n  PQXY \n2 OFEJ\n" \
    "PQXY 1\nabc\n  OFEJ \n2 OFEJ\n" \
    "PQXY 1\nabc\ndef\nPQXY 2\n2 OFEJ\n" \
; do
    echo "$i:"
    printf "$i" | awk '
        /^PQXY/     { s = $0; c = 1; next}
        /OFEJ$/     { if (c == 1) { print s""ORS""$0; c = 0 }; next }
        /OFEJ|PQXY/ { c = 0; next }
        c == 1      { s = s""ORS""$0 }' | sed 's/^/    /
    '
done

这是输出,您可以看到它的实际效果:

PQXY 1\nabc\n2 OFEJ\n:
    PQXY 1
    abc
    2 OFEJ
PQXY 1\nabc\n2 OFEJx\n:
PQXY 1\nabc\n  PQXY \n2 OFEJ\n:
PQXY 1\nabc\n  OFEJ \n2 OFEJ\n:
PQXY 1\nabc\ndef\nPQXY 2\n2 OFEJ\n:
    PQXY 2
    2 OFEJ

(a) 根据我的经验,如果您使用 grep 样式的正则表达式尝试了三件事但没有成功,那么转向更高级的工具通常会更快:-)


(b) 是的,我知道它是用bash 而不是zsh 写的,但那是因为:

  • 这是一个测试程序,向您展示awk 有效,因此使用的语言无关紧要;和
  • 我更喜欢bash tahn zsh :-)

【讨论】:

  • 它解决了错误。但计数显示为零。它不正确。你能检查更新的问题吗
  • @Santhosh,正则表达式错误是一个 不同 问题,与您遇到的错误无关。您通常应该对每个问题提出 一个 问题,如果还有更多问题,请提出另一个问题。这样既可以保持问题和答案的兼容性,又可以更好地针对未来搜索的人的特定问题。
  • 你回答了主要问题。正则表达式部分应该是另一个问题
  • 感谢 awk 解决方案。我喜欢用 awk 做事,但只是因为我使用 perl 的前瞻功能
  • 感谢您通过示例数据展示如何使用 awk。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多