我是 GNU/Linux 和正则表达式的新手。最近我一直在尝试掌握正则表达式。到目前为止,我觉得我已经有了相当扎实的基础理解。我现在正在挖掘PCRE。
这是我正在使用的练习文本文件:
01234 567890
01111-222111
09876.543210
我可以通过执行以下操作成功匹配数字:
(\d{5})[-.]?\s*?(\d{6})
现在我想创建一个非捕获组,以便错过前 5 位数字,只匹配最后 6 位。所以我想我投入(?:)
代表非捕获组,然后是我不想被捕获的任何内容,对吧?那么那就是
(?:\d{5})[-.]?\s*?(\d{6})
我这样做了,在我的终端中使用grep -Po
PCRE 并显示输出,我仍然得到完全匹配,就好像非捕获组不适用一样。
有什么指导吗?
答案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
您可以使用以下命令获得您想要的输出pcregrep
Linux 上的命令。它扩展了-o
选项,它允许您输出选定的捕获组。由于您想要第二组,因此您可以使用 -onumber
-o2
:
$ pcregrep -o2 '(\d{5})[-.]?\s*?(\d{6})' input
567890
222111
543210