如何使用正则表达式查找重叠匹配?

Posted

技术标签:

【中文标题】如何使用正则表达式查找重叠匹配?【英文标题】:How to find overlapping matches with a regexp? 【发布时间】:2012-07-10 23:10:09 【问题描述】:
>>> match = re.findall(r'\w\w', 'hello')
>>> print match
['he', 'll']

由于 \w\w 表示两个字符,因此需要“he​​”和“ll”。但是为什么 'el' 和 'lo' 匹配正则表达式?

>>> match1 = re.findall(r'el', 'hello')
>>> print match1
['el']
>>>

【问题讨论】:

Lookahead 【参考方案1】:

findall 默认情况下不会产生重叠匹配。然而,这个表达式确实:

>>> re.findall(r'(?=(\w\w))', 'hello')
['he', 'el', 'll', 'lo']

这里(?=...)lookahead assertion

(?=...) 匹配如果 ... 匹配下一个,但不消耗任何 细绳。这称为前瞻断言。例如, Isaac (?=Asimov) 将匹配 'Isaac ',前提是它后面跟着 'Asimov'

【讨论】:

但我不明白如果它在积极的前瞻断言中,为什么它会前进到下一个字母。请解释一下好吗? @MrZH6 我猜这是由于组捕获(\w\w 周围的大括号)。实际匹配仍然是一个空字符串,而第 1 组用 \w\w 填充(您可以在regex101.com 进行测试)。所以我相信它会在一个组中捕获它,但不会超过它,因为匹配是零长度的。而python的re.findall将打印捕获的组docs.python.org/3/library/re.html#re.findall【参考方案2】:

您可以使用new Python regex module,它支持重叠匹配。

>>> import regex as re
>>> match = re.findall(r'\w\w', 'hello', overlapped=True)
>>> print match
['he', 'el', 'll', 'lo']

【讨论】:

【参考方案3】:

除了零长度断言外,输入中的字符将始终在匹配中被消耗。如果您想在输入字符串中多次捕获某些字符,则需要在正则表达式中进行零长度断言。

有几个零长度断言(例如^(输入/行的开头)、$(输入/行的结尾)、\b(字边界)),但环顾四周(@987654324 @positive look-behind 和 (?=)positive look-ahead)是您可以从输入中捕获重叠文本的唯一方法。否定环视((?<!)negative look-behind,(?!)negative look-ahead)在这里不是很有用:如果它们断言为真,则内部捕获失败;如果他们断言为假,则匹配失败。这些断言是零长度的(如前所述),这意味着它们将断言而不消耗输入字符串中的字符。如果断言通过,它们实际上将匹配空字符串。

应用上述知识,适用于您的情况的正则表达式将是:

(?=(\w\w))

【讨论】:

【参考方案4】:

我不是正则表达式专家,但我想回答我类似的question。

如果您想使用具有前瞻功能的捕获组:

示例正则表达式:(\d)(?=.\1)

字符串:5252

这将匹配前 5 个以及前 2 个

(\d)是做一个捕获组,(?=\d\1)是匹配捕获组1后面的任何数字而不消耗字符串,因此允许重叠

【讨论】:

以上是关于如何使用正则表达式查找重叠匹配?的主要内容,如果未能解决你的问题,请参考以下文章

替换字符串中的重叠匹配项(正则表达式或字符串操作)

如何检测两个正则表达式在它们可以匹配的字符串中是不是重叠?

如何将重叠字符串与正则表达式匹配?

Vim 多行正则表达式给出重叠匹配

如何 grep/perl/awk 重叠正则表达式

如何制作将多个模式匹配到同一索引的python正则表达式