为什么两个标签之间的 grep 不适用于选项 -z?怎么修?

为什么两个标签之间的 grep 不适用于选项 -z?怎么修?

这个案例:

$ cat t01.txt
xxxyyyzzz

$ cat t01.txt | grep -Po '(?<=xxx).*(?=zzz)'

结果是:

yyy

这是预期的。

然而,这个案例:

$ cat t02.txt
xxx
yyy
zzz

$ cat t02.txt | grep -Pzo '(?<=xxx).*(?=zzz)'

结果是:

<nothing>

这是出乎意料的。

为什么以及如何解决?

答案1

因为默认情况下,.与 Perl 正则表达式中的换行符不匹配。您需要显式匹配它,或者使用s正则表达式的标志:

$ < t02.txt grep -Pzo '(?<=xxx\n).*\n(?=zzz)'
yyy
$ < t02.txt grep -Pzo '(?s)(?<=xxx).*(?=zzz)'

yyy

参见例如perlre手册页

在“元字符”部分:

.   Match any single character except newline    Not in []
    (under /s, includes newline)

并在“修饰符”中:

s
将字符串视为单行。也就是说,更改"."为匹配任何字符,甚至是换行符,通常它不会匹配。

答案2

这实际上是预期的行为。.包括除换行符之外的任何字符。您正在寻找的正则表达式是:

(?<=xxx)\n*.*\n*(?=zzz)

这是一个测试正则表达式的好网站,它也对它的每个部分都有解释,所以你总是知道它为什么会这样:https://regex101.com

相关内容