为什么正则(\d)\d\1无法匹配交替重复数字?Python re.findall仅返回5
原有正则不符合预期的核心原因
你碰到的返回结果偏差,是Python re模块两个基础机制共同导致的:
re.findall的返回规则:当正则存在捕获组时,函数默认返回每个匹配对应的捕获组内容列表,而非完整的匹配字符串。你写的(\d)\d\1只设置了1个捕获组,就算成功命中完整的525三字符片段,也只会返回捕获组记录的单个数字,不会返回片段中间的字符、以及和第一个数字同值的尾部字符。- 非重叠匹配的默认逻辑:Python re模块扫描字符串时,每完成一次匹配,下一次的扫描起点会直接跳到本次匹配的结束位置之后,不会主动查找和已匹配片段重叠的内容。对应你的示例字符串
552523,扫描过程为:从头开始寻找符合
(\d)\d\1的片段时,第一个命中的是索引1到3位置的525(字符为位置1的5、位置2的2、位置3的5),匹配结束在位置3,下一次扫描直接从位置4开始;而位于索引2到4位置的252片段,因为和上一次的匹配共享了位置3的字符,属于重叠内容,直接被跳过。
这也是你运行代码后只返回单个5、没有拿到后续2的根本原因。
实现目标需求的可行方法
要拿到示例中(5,5)、(2,2)的数字配对,只需要对正则逻辑做两处调整:
- 把需要提取的两个相同数字都设置为独立捕获组,方便
findall直接返回配对内容,替代原来单捕获组的写法。 - 用零宽正向前瞻结构实现重叠位置的扫描,避免因为非重叠匹配漏掉跨位置的符合规则的片段。
调整后的正则表达式为:(?=(\d)\d(\1))
这个正则的逻辑是:从字符串的每个位置开始,向后窥探3个字符的长度,不实际消耗当前扫描位置的字符(零宽特性),只要发现第一个和第三个字符是相同数字(符合ABA的交替重复结构),就把这两个相同数字作为捕获组内容记录下来。
对应示例的实际运行效果:
示例代码:
re.findall(r'(?=(\d)\d(\1))', '552523')
运行返回:[('5', '5'), ('2', '2')]
如果需要得到整数类型的配对,只要把返回结果里的字符串元素转换为对应整数即可。
内容的提问来源于stack exchange,提问作者Sasi Kanth
相关产品推荐
相关产品推荐

