PCRE-regex 使用 grep 排除捕获组

PCRE-regex 使用 grep 排除捕获组

我正在使用GNU grepPCRE-P正则表达式支持来匹配文件中的字符串。输入文件包含包含以下字符串的行:

FOO_1BAR.zoo.2.someString:More-RandomString (string here too): 0.45654343

我想捕获上面一行中的数字2和数字。0.45654343我使用了正则表达式

grep -Po ".zoo.\K[\d+](.*):\ (.*)$" file

但这给我带来的结果是

2.someString:More-RandomString (string here too): 0.45654343

我能够从第一个捕获组中获取第一个数字2,并且还可以匹配行末尾的捕获组。但我无法跳过两个捕获组之间的单词/行。

我确实知道我有一个小组(.*)正在捕捉中间的这些词。我试图做的是包含另一个\K来忽略它

grep -Po ".zoo.\K[\d+](.*):\K (.*)$" file

但这只给了我第二个捕获组作为0.556984.

还有一个非捕获组,其(?:)语法为

grep -Po ".zoo.\K[\d+](?=.someString:More-RandomString (string here too)):\ (.*)$"

但这没有给我带来什么。我在这里缺少什么?

答案1

grep的名字出现在g/re/p ed命令之后。它的主要目的是打印与正则表达式匹配的行。它的职责不是编辑这些行的内容。你有sed(流编辑器)或awk为此。

现在,grep从 GNU 开始,一些实现grep添加了一个-o选项来打印每行的匹配部分(正则表达式匹配的内容,而不是其捕获组的匹配部分)。你已经有了一些grep类似 GNU 的实现(使用-P)或者pcregrep支持 PCRE 的正则表达式。

pcregrep实际上添加了一个-o<n>选项来打印捕获组的内容。所以你可以这样做:

pcregrep -o1 -o2 --om-separator=' ' '.zoo.(\d+).*:\s+(.*)'

但在这里,明显的标准解决方案是使用sed

sed -n 's/^.*\.zoo\.\([0-9]\{1,\}\).*:[[:space:]]\{1,\}/\1 /p'

或者,如果您想要 perl 正则表达式,请使用 perl:

perl -lne 'print "$1 $2" if /\.zoo\.(\d+).*:\s+(.*)/'

使用 GNU grep,如果您不介意匹配项出现在不同的行上,您可以这样做:

$ grep -Po '\.zoo\.\K\d+|:\s+\K.*' < file
2
0.45654343

请注意,虽然\K重置了匹配部分的开始,但这并不意味着您可以摆脱交替重叠的两个部分。

grep -Po '.zoo.(\K\d+|.:\K。)'

不起作用,就像echo foobar | grep -Po 'foo|foob'不起作用(同时打印foofoob)。foo|foob首先匹配foo,然后grep在 后的输入中查找潜在的其他匹配项foo,因此从bof开始bar,因此之后无法找到更多匹配项。

上面的,我们只在交替的第二部分中grep -Po '\.zoo\.\K\d+|:\s+\K.*'查找。:<spaces><anything>这确实匹配后面的部分.zoo.<digits>,但这也意味着它会:<spaces><anything>在输入中的任何位置找到那些内容,而不仅仅是当它们跟随时.zoo.<digits>

不过,有一种方法可以解决这个问题,即使用另一个 PCRE 特殊运算符:\G\G匹配主题的开头。对于单个匹配,这相当于^,但对于多个匹配(想想中的sed/perl标志),就像 with where尝试查找行中的所有匹配,它也在上一个匹配结束后匹配。所以如果你做到了:gs/.../.../g-ogrep

grep -Po '\.zoo\.\K\d+|(?!^)\G.*:\s+\K.*'

(?!^)负前瞻运算符在哪里,这意味着不在行的开头,它\G只会在上一次成功(非空)匹配之后匹配,因此.*:\s+\K.*只有在上一次成功匹配之后才会匹配,并且只能是这个.foo.<digits>匹配,因为交替的其他部分匹配到行尾。

在这样的输入上:

.zoo.1.zoo.2 tar: blah

那会输出:

1
2
blah

尽管。如果您不希望这样,您还希望交替的第一部分仅在行的开头匹配。就像是

grep -Po '^.*?\.zoo\.\K\d+|(?!^)\G.*:\s+\K.*'

它仍然在像or 这样的2输入上输出。您可以在交替的第一部分使用前瞻运算符来解决这个问题,并在后面查找至少一个非空格(也可以用来 避免非字符问题).zoo.2 no colon character.zoo.2 blah::<spaces>$

grep -Po '^.*?\.zoo\.\K\d+(?=.*:\s+\S.*$)|(?!^)\G.*:\s+\K\S.*$'

您可能需要几页注释来解释该正则表达式,所以我仍然会选择直接sed/perl解决方案......

相关内容