正则表达式 - 不同的字符串相同的匹配

8

我明白模式r'([a-z]+)\1+'在搜索字符串中寻找重复的多字符模式,但我不明白为什么在k2的情况下答案不是'aaaaa'(5个'a'):

import re
k1 = re.search(r'([a-z]+)\1+', 'aaaa')
k2 = re.search(r'([a-z]+)\1+', 'aaaaa')
k3 = re.search(r'([a-z]+)\1+', 'aaaaaa')
print(k1)  # <_sre.SRE_Match object; span=(0, 4), match='aaaa'>
print(k2)  # <_sre.SRE_Match object; span=(0, 4), match='aaaa'>
print(k3)  # <_sre.SRE_Match object; span=(0, 6), match='aaaaaa'>

Python 3.6.1


请逐步解释您当前的推理过程。否则,无法确定真正困扰您的问题是什么。 - Mad Physicist
2
https://regex101.com/ 是一个很好的网站,可以帮助你学习正则表达式(我与其无关!) - AlG
1
它必须是偶数个字符,因为你要重复一个事物两次。之所以是两次,是因为‘+’是贪婪的,并且第一个具有优先级。 - Mad Physicist
1
无论有多少个 x(x)x 的长度都不可能是奇数。 - Jongware
这是因为 + 是贪婪的。它试图尽可能匹配更多内容。要么将其更改为 ([a-z]+?)\1+,要么使用锚点 ([a-z]+)\1+\b - ctwheels
只是提醒一下,这个([a-z]+)将匹配与\1完全相同的数量和内容。因此,在\1中添加一个+量词不会匹配超过第1组匹配的内容,这是不可能的。这也会导致一个均匀的匹配。如果你将它改为([a-z])\1+,它将匹配第1组捕获的2个或更多内容。 - user557597
2个回答

6

因为 + 是贪婪的。

发生的情况是 ([a-z]+) 首先匹配了 'aaaaa',然后回溯直到 \1+ 匹配了字符串,并停止。因为 'aa' 是第一个让 \1 成功匹配的 ([a-z]+) 值,所以返回它。


2
这里的关键概念是“回溯”。每当一个模式包含具有不同长度的量化子模式时,正则表达式引擎可以以各种方式匹配字符串,一旦在量化部分之后的某个正则表达式部分无法匹配某个子字符串,它就可以“回溯”,即释放属于量化模式的字符并尝试与随后的子模式匹配。
看看更大的图景:

enter image description here

让我们先看看较短的字符串是否匹配,然后再看长的例子......为什么 "a" 没有匹配?因为由于 "[a-z]+ "和 "\1+" 要求至少匹配一个字符,所以必须至少有两个字符。"aa" 匹配了,因为第一个 "([a-z]+)" 先匹配了整个字符串,然后回溯以适应 "\1+" 模式的一些文本(并匹配第二个 "a"),因此存在匹配。三个 "a" 的字符串 "aaa" 作为一个整体匹配,因为第一个 "([a-z]+)" 先匹配了整个字符串,然后回溯以适应 "\1+" 模式的一些文本(请注意,捕获组只需要保存一个 "a",当尝试两个 "aa" 时,"\1+" 无法匹配最后的第三个 "a"),并且存在三个 "a" 的匹配。现在,来看看问题中的例子。

整个字符串 aaaa 完全匹配的方式与 aa 的匹配方式类似:捕获组模式首先抓取整个 aaaa,然后回溯,因为 \1+ 也必须“找到”一些文本,并且正则表达式引擎尝试将 aaa 捕获到第一组中。然而,\1+ 无法匹配 3 个 a,因此回溯继续进行,当第一组中有两个 a 时,定量化反向引用匹配最后两个 a

现在考虑 k2 的情况:

字符串 aaaaa 的匹配方式如下:

"
  • aaaaa被抓取并与([a-z]+)部分一起放入第1组。
  • \1+找不到任何文本,引擎尝试以不同的方式匹配字符串,因为+量词使得\1+前面的部分可以匹配不同的文本
  • 尝试了aaaa(=放入第1组),但无济于事,因为\1+不匹配(因为然后\1尝试匹配aaaa,但在字符串末尾之前只剩下一个a
  • 再次尝试了aaa,但也无济于事(因为\1尝试匹配aaa,但只剩下两个a
  • aa放入第1组,\1匹配第三和第四个a,这是唯一的匹配,因为字符串中只剩下一个a
"
这是一个字符串匹配的示例方案

enter image description here

最后一个a无法匹配:

enter image description here


1
感谢您的详细解释。 - Maxim Andreev
不客气。顺便提一下:图像中的红色箭头表示回溯步骤。绿色高亮文本是当前尝试的模式的一部分。蓝色选择是匹配当前尝试的子模式的文本。 - Wiktor Stribiżew

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接