为什么正则表达式的“非捕获”组不工作?

73 投票
7 回答
79820 浏览
提问于 2025-04-15 21:58

在下面的代码片段中,非捕获组 "(?:aaa)" 应该在匹配结果中被忽略,

所以结果应该只有 "_bbb"

但是,我得到的匹配结果却是 "aaa_bbb";只有当我指定 group(2) 时,它才会显示 "_bbb"

>>> import re
>>> s = "aaa_bbb"
>>> print(re.match(r"(?:aaa)(_bbb)", s).group())

aaa_bbb

7 个回答

3

TFM:

class re.MatchObject

group([group1, ...])

这个方法可以返回匹配结果中的一个或多个子组。如果你只给它一个参数,它会返回一个字符串;如果你给它多个参数,它会返回一个包含每个参数对应结果的元组。如果不传任何参数,默认返回的是第一个组(也就是整个匹配的内容)。如果你传入的参数是零,那么返回的就是整个匹配的字符串。

148

我觉得你对“非捕获组”的概念有些误解。非捕获组匹配的内容仍然会成为整个正则表达式匹配的一部分。

正则表达式 (?:aaa)(_bbb)(aaa)(_bbb) 都会返回 aaa_bbb 作为整体匹配结果。它们的区别在于,第一个正则表达式有一个捕获组,会返回 _bbb 作为匹配结果,而第二个正则表达式有两个捕获组,分别返回 aaa_bbb 作为匹配结果。在你的Python代码中,要获取 _bbb,你需要用第一个正则表达式的 group(1),而用第二个正则表达式则需要 group(2)

非捕获组的主要好处是,你可以把它们添加到正则表达式中,而不会影响捕获组的编号。而且,它们在性能上也稍微好一些,因为正则引擎不需要跟踪非捕获组匹配的文本。

如果你真的想把 aaa 从整体正则匹配中排除,那你需要使用前后查找。在这种情况下,正向前查找就能解决问题:(?<=aaa)_bbb。使用这个正则表达式时,group() 在Python中会返回 _bbb,不需要捕获组。

我的建议是,如果你可以使用捕获组来获取正则匹配的一部分,最好还是用这种方法,而不是使用前后查找。

63

group()group(0) 会返回整个匹配的结果。后面的组才是真正的捕获组。

>>> print (re.match(r"(?:aaa)(_bbb)", string1).group(0))
aaa_bbb
>>> print (re.match(r"(?:aaa)(_bbb)", string1).group(1))
_bbb
>>> print (re.match(r"(?:aaa)(_bbb)", string1).group(2))
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
IndexError: no such group

如果你想要和 group() 一样的效果,可以这样做:

" ".join(re.match(r"(?:aaa)(_bbb)", string1).groups())

撰写回答