pcregrep 或 grep:使用先行搜索不起作用
pcregrep or grep: searching with lookaheads not working
我正在尝试搜索具有前瞻性的正则表达式,它在 pcregrep 或 grep 中不起作用
我要搜索部分片段
- 可能跨越多行,
- 在行首以 PQXY 开头并且
- 在行尾以 OFEJ 结束,
- 中间不包含 PQXY 或 OFEJ
一般我在 sublime text 查找中使用以下内容并且效果很好
(?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
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 = [=12=]; c = 1; next}
/OFEJ$/ { if (c == 1) { print s""ORS""[=12=]; c = 0 }; next }
/OFEJ|PQXY/ { c = 0; next }
c == 1 { s = s""ORS""[=12=] }' 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 = [=13=]; c = 1; next}
/OFEJ$/ { if (c == 1) { print s""ORS""[=13=]; c = 0 }; next }
/OFEJ|PQXY/ { c = 0; next }
c == 1 { s = s""ORS""[=13=] }' | 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
:-)
使用gnu grep
:
grep -ozP '(?ms)^PQXY(?:(?!PQXY|OFEJ).)*OFEJ(\R|\z)' file
您必须使用 -z
选项将输入和输出数据视为行序列,每行以零字节结尾。
确保为您的模式使用单引号,这样 shell 的历史模块就不会尝试处理 !
。
- 添加了
(?m)
(多行)修饰符以允许在正则表达式中为每一行使用 ^
和 $
- 使用
(\R|\z)
允许结束模式在文件末尾没有换行符的情况下结束。 \R
匹配任何换行符,包括 unicode 字符,\z
匹配输入结尾。
pcregrep
中的等价解
pcregrep -M '(?s)^PQXY(?:(?!PQXY|OFEJ).)*OFEJ(\R|\z)' file
-M
在 pcregrep
中启用多行选项。
我正在尝试搜索具有前瞻性的正则表达式,它在 pcregrep 或 grep 中不起作用
我要搜索部分片段
- 可能跨越多行,
- 在行首以 PQXY 开头并且
- 在行尾以 OFEJ 结束,
- 中间不包含 PQXY 或 OFEJ
一般我在 sublime text 查找中使用以下内容并且效果很好
(?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
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 = [=12=]; c = 1; next}
/OFEJ$/ { if (c == 1) { print s""ORS""[=12=]; c = 0 }; next }
/OFEJ|PQXY/ { c = 0; next }
c == 1 { s = s""ORS""[=12=] }' 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 = [=13=]; c = 1; next}
/OFEJ$/ { if (c == 1) { print s""ORS""[=13=]; c = 0 }; next }
/OFEJ|PQXY/ { c = 0; next }
c == 1 { s = s""ORS""[=13=] }' | 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
tahnzsh
:-)
使用gnu grep
:
grep -ozP '(?ms)^PQXY(?:(?!PQXY|OFEJ).)*OFEJ(\R|\z)' file
您必须使用
-z
选项将输入和输出数据视为行序列,每行以零字节结尾。确保为您的模式使用单引号,这样 shell 的历史模块就不会尝试处理
!
。- 添加了
(?m)
(多行)修饰符以允许在正则表达式中为每一行使用^
和$
- 使用
(\R|\z)
允许结束模式在文件末尾没有换行符的情况下结束。\R
匹配任何换行符,包括 unicode 字符,\z
匹配输入结尾。
pcregrep
pcregrep -M '(?s)^PQXY(?:(?!PQXY|OFEJ).)*OFEJ(\R|\z)' file
-M
在 pcregrep
中启用多行选项。