使用 grep 帮助处理这个非捕获组?

使用 grep 帮助处理这个非捕获组?

我是 GNU/Linux 和正则表达式的新手。最近我一直在尝试掌握正则表达式。到目前为止,我觉得我已经有了相当扎实的基础理解。我现在正在挖掘PCRE。

这是我正在使用的练习文本文件:

01234 567890

01111-222111

09876.543210

我可以通过执行以下操作成功匹配数字:

(\d{5})[-.]?\s*?(\d{6})

现在我想创建一个非捕获组,以便错过前 5 位数字,只匹配最后 6 位。所以我想我投入(?:)代表非捕获组,然后是我不想被捕获的任何内容,对吧?那么那就是

(?:\d{5})[-.]?\s*?(\d{6})

我这样做了,在我的终端中使用grep -PoPCRE 并显示输出,我仍然得到完全匹配,就好像非捕获组不适用一样。

有什么指导吗?

答案1

-o使用or选项时,捕获不会影响 grep 认为是匹配部分的内容--only-matching。所有非捕获意味着您不打算将组计为可用反向引用之一(或替换,在可以选择替换的上下文中)。

例如:

$ printf 'aba\nabb\nabc\n' | grep -Po '(a)(b)'
ab
ab
ab
$ printf 'aba\nabb\nabc\n' | grep -Po '(a)(b)\1'
aba
$ printf 'aba\nabb\nabc\n' | grep -Po '(?:a)(b)\1'
abb

可能您在这种情况下正在寻找的是零长度后行断言

printf 'aba\nabb\nabc\n' | grep -Po '(?<=a)b'
b
b
b

\K“靠左行驶”的主张

$ printf 'aba\nabb\nabc\n' | grep -Po 'a\Kb'
b
b
b

(后者稍微灵活一些,因为它允许可变长度匹配)。

例如

$ grep -Po '\d{5}[-.]?\s*\K\d{6}' file
567890
222111
543210

答案2

您使用的正则表达式似乎太复杂,无法仅匹配中间的字符,可以是 a -、 a.或空格。为什么你需要[-.]?\s*?。内容如下:匹配 a-或 a .(可选(`?)),后跟空格(嗯,真的(来自 man pcrepattern):默认的 \s 字符现在为 HT (9)、LF (10)、VT (11)、FF (12)、CR (13) 和 space (32))。好吧,实际上,在惰性模式下有几个空格(*?)。

在我看来,它只需要[ .-]简单,一个字符,一个空格、一个点或一个破折号。这个正则表达式:

(\d{5})[-. ](\d{6})

最好的尝试地点(学习正则表达式的唯一真正方法)是访问 regex101.com 并尝试。这里我创建了这篇文章的示例详细(在 PCRE 中,是的)。

你可以看到,在替换中,你所问的是什么,我放置了这个替换:

(one:\1) (two:\2) (three:3)

您可以看到,在每一行上,整个匹配项(从正则表达式的开头到结尾)(而不是周围的文本)都被该字符串替换,其中\1\2被转换为捕获的值。每人一份(...)

如果你想让第一个(...)非捕获,那么就只有捕获组,替换应更改为:

(one:1) (two:\1) (three:3)

只有一个\1。否则更换会失败。

如果要替换整行,请使其从头到尾匹配整行:

^.*(?:\d{5})[-. ](\d{6}).*$

并进行替换仅\1打印最后一组数字。

现在,关于 grep。 Grep 没有替代品,有一些东西“有点”有帮助,但不是一个很好的等价物:\K

grep -Po '^.*\d{5}[-. ]\K\d{6}' file

一个重要的想法是,-o旨在给出正则表达式匹配的所有内容,是的,整个正则表达式,而不是每个匹配的括号。

要使用真正的替代品(或替代品 ( s///)),您需要sed(但它使用 BRE 而不是 PCRE):

$ sed 's/^.*\([0-9]\{5\}\)[-. ]\([0-9]\{6\}\).*$/ \2 \1 /' file
 567890 01234 
 222111 01111 
 543210 09876

这确实是一个替换,并且允许更改顺序(或重复)。

答案3

如果您只想grep输出最后 6 个字符是数字的行块,那么只需说

grep -Po "\d{6}$" file

如果您想确定分隔符,请添加后面的外观

grep -Po "(?<=[-. ])\d{6}$" file

或者如果位数不确定

grep -Po "\d+$" file

在这两种情况下,只需锚定到行尾并匹配回来即可。

我发现最好的计划是通常不处理你不需要处理的部分(尽管有每一个为了学习而以困难的方式做事的美德……坚持下去;D)。

答案4

您可以使用以下命令获得您想要的输出pcregrepLinux 上的命令。它扩展了-o选项,它允许您输出选定的捕获组。由于您想要第二组,因此您可以使用 -onumber-o2

$ pcregrep -o2 '(\d{5})[-.]?\s*?(\d{6})' input
567890
222111
543210

相关内容