如何让 "grep -zoP" 分别显示每场比赛?

How can I get "grep -zoP" to display every match separately?

我在这个表格上有一个文件:

X/this is the first match/blabla
X-this is
the second match-

and here we have some fluff.

我想提取出现在“X”之后和相同标记之间的所有内容。所以如果我有“X+match+”,我想得到“match”,因为它出现在“X”之后和标记“+”之间。

因此,对于给定的示例文件,我希望得到以下输出:

this is the first match

然后

this is
the second match

我设法通过使用以下方法获得 X 后跟标记之间的所有内容:

grep -zPo '(?<=X(.))(.|\n)+(?=)' file

即:

所以这很好用,唯一的问题来自输出的显示:

$ grep -zPo '(?<=X(.))(.|\n)+(?=)' file
this is the first matchthis is
the second match

如您所见,所有匹配项都出现在一起,“这是第一个匹配项”后面跟着“这是第二个匹配项”,完全没有分隔符。我知道这来自“-z”的使用,它将所有文件 视为一组行,每行以零字节(ASCII NUL 字符)而不是换行符终止 (引用“man grep”)。

那么:有没有办法分别获得所有这些结果?

我也在 GNU Awk 中尝试过:

awk 'match([=16=], /X(.)(\n|.*)/, a) {print a[1]}' file

但甚至 (\n|.*) 都不起作用。

awk 不支持正则表达式定义中的反向引用。

解决方法:

$ grep -zPo '(?s)(?<=X(.)).+(?=)' ip.txt | tr '[=10=]' '\n'
this is the first match
this is
the second match

# with ripgrep, which supports multiline matching
$ rg -NoUP '(?s)(?<=X(.)).+(?=)' ip.txt
this is the first match
this is
the second match

也可以用(?s)X(.)\K.+(?=)代替(?s)(?<=X(.)).+(?=)。此外,您可能希望在此处使用非贪婪量词以避免将 match+xyz+foobaz 匹配为输入 X+match+xyz+foobaz+


perl

$ perl -0777 -nE 'say $& while(/X(.)\K.+(?=)/sg)' ip.txt
this is the first match
this is
the second match

这个用例有点问题,因为一旦打印匹配项,您就会丢失有关分隔符确切位置的信息。但如果可以接受,请尝试通过管道传输到 xargs -r0.

grep -zPo '(?<=X(.))(.|\n)+(?=)' file | xargs -r0

这些选项是 GNU 扩展,但 grep -z 和(大部分)grep -P 也是如此,所以也许这是可以接受的。

使用 GNU awk 实现多字符 RS、RT 和 gensub(),无需将整个文件读入内存:

$ awk -v RS='X.' 'NR>1{print "<" gensub(end".*","",1) ">"} {end=substr(RT,2,1)}' file
<this is the first match>
<this is
the second match>

显然我添加了“<”和“>”所以你可以看到每个输出记录的位置starts/ends。

上面假设 X 之后的字符不是不重复的正则表达式元字符(例如 .^[ 等)所以YMMV

这是另一个使用 RSRT 的 gnu-awk 解决方案:

awk -v RS='X.' 'ch != "" && n=index([=10=], ch) {
   print substr([=10=], 1, n-1)
}
RT {
   ch = substr(RT, 2, 1)
}' file
this is the first match
this is
the second match

GNU grep -z 终止 input/output 包含空字符的记录(与其他工具结合使用,例如 sort -z)。 pcregrep 不会这样做:

pcregrep -Mo2 '(?s)X(.)(.+?)' file
使用

-o<em>number</em> 代替环顾四周。 ? 添加了惰性量词(以防 稍后出现)。