s = "aaa_bbb"
for pattern in [r"(?:aaa)(_bbb)", r"aaa(_bbb)", r"(?:aaa(_bbb))"]:
m = re.match(pattern, s)
print(pattern)
print("=" * len(pattern))
print(f"groups(): {m.groups()}")
for i in range(1, len(m.groups()) + 1):
print(f" group({i}): {m.group(i)}")
print()
7条答案
按热度按时间cnwbcb6i1#
我想你误解了“非捕获组”的概念,由非捕获组匹配的文本仍然是整个正则表达式匹配的一部分。
正则表达式
(?:aaa)(_bbb)
和正则表达式(aaa)(_bbb)
都返回aaa_bbb
作为总体匹配,区别在于第一个正则表达式有一个捕获组,返回_bbb
作为匹配,而第二个正则表达式有两个捕获组,返回aaa
和_bbb
作为各自的匹配,在Python代码中,要获得_bbb
,你需要对第一个正则表达式使用group(1)
,对第二个正则表达式使用group(2)
。非捕获组的主要好处是,你可以将它们添加到正则表达式中,而不会打乱正则表达式中捕获组的编号。它们还提供了(稍微)更好的性能,因为正则表达式引擎不必跟踪非捕获组匹配的文本。
如果你真的想把
aaa
从整个正则表达式匹配中排除,那么你需要使用lookaround。在这种情况下,正向后查找可以达到目的:(?<=aaa)_bbb
。使用这个正则表达式,group()
在Python中返回_bbb
。不需要捕获组。我的建议是,如果您有能力使用捕获组来获取正则表达式匹配的一部分,请使用该方法而不是lookaround。
gt0wga4j2#
group()
和group(0)
将返回整个匹配。后续组是实际的捕获组。如果您想要与
group()
相同的行为:" ".join(re.match(r"(?:aaa)(_bbb)", string1).groups())
l5tcr1uw3#
试试看:
group()
与group(0)
相同,并且组0
始终存在,这是整个RE匹配。omhiaaxx4#
TFM:
class re.MatchObject
group([group1, ...])
返回匹配项的一个或多个子组。如果有单个参数,则结果为单个字符串;如果有多个参数,则结果是一个元组,每个参数一个项目。如果没有参数,group 1默认为零(返回整个匹配项)。如果groupN参数为零,则相应的返回值为整个匹配字符串。
t0ybt7op5#
必须指定
group(1)
才能只获取括号中的部分(本例中为_bbb
)。不带参数的
group()
将返回与完整正则表达式匹配的整个字符串,而不管它的某些部分是否由括号额外捕获。uubf1zoe6#
在match对象上使用groups方法而不是group。它返回所有捕获缓冲区的列表。没有参数的group方法返回正则表达式的整个匹配。
hfsqlsce7#
让我们一起来看看扬·戈瓦尔特的回答:
非捕获组的主要好处是,您可以将它们添加到正则表达式中,而不会打乱正则表达式中捕获组的编号。
为什么要添加一个不会打乱组编号的组呢?
OP的例子
r"(?:aaa)(_bbb)"
吸引了我的注意力(和大脑)到"aaa",但它没有什么特别之处......对我来说,它只是看起来与真正重要的东西"_bbb"相邻。我认为它实际上应该是其中之一:
r"aaa(_bbb)"
:如果"aaa"对您/我们如何读取正则表达式不重要,则"aaa"对我们没有意义r"(?:aaa(_bbb))"
:如果"aaa_bbb"是一个单独的东西,我们应该(在心理上)作为一个整体来考虑,但最终我们只使用"_bbb"从正则表达式引擎的Angular 来看,这三个函数都是等效的:
对于一个真实的例子,我想解析一个类Unix的time命令的输出:
我最初的Python正则表达式是:
这就给了我正确的分组:
但是值末尾的标签一直把我的眼睛抛开,我一直看到"real\s+(\d +.\d+)"而不是"(\d +.\d+)real"。
我可以尝试添加括号来直观地区分"元组",这在视觉上对我来说稍微好一点:
但这打破了我想要的分组逻辑:
让这些元组 * 不分组 * 让我的元组有了更好的视觉效果(我的眼睛仍然会来回移动,但至少有了清晰的边界):
并且不考虑分组的逻辑