正如@Tomalak 所说,正则表达式引擎没有内置的重叠匹配概念,因此找不到“聪明”的解决方案(结果证明是错误的- 见下文)。但是用循环来做这件事很简单:
import re
pat = re.compile("ATG(?:(?!TAA|TGA|TAG)\w\w\w)*")
s = 'GATGDTATGDTAAAA'
i = 0
while True:
m = pat.search(s, i)
if m:
start, end = m.span()
print "match at {}:{} {!r}".format(start, end, m.group())
i = start + 1
else:
break
显示
match at 1:10 'ATGDTATGD'
match at 6:15 'ATGDTAAAA'
它的工作原理是在最后一个匹配开始后的一个字符之后重新开始搜索,直到找不到更多匹配。
“聪明”还是定时炸弹?
如果您想危险地生活,您可以对原始finditer
代码进行 2 个字符的更改:
print it.start(1)
print it.end(1)
也就是说,获取第一个 ( 1
) 捕获组的开始和结束。通过不传递参数,您将获得整个匹配的开始和结束 - 但当然匹配的断言总是匹配空字符串(因此开始和结束是相等的)。
我说这是危险的生活,因为断言中捕获组的语义(无论是向前还是向后,正面或负面,......)充其量是模糊的。很难说您是否在这里偶然发现了错误(或实施事故)!可爱的 :-)
编辑:经过一夜的睡眠和对 Python-Dev 的简短讨论,我相信这种行为是故意的(而且也很可靠)。要查找正则表达式 R 的所有(可能重叠!)匹配项,请将其包装如下:
pat = re.compile("(?=(" + R + "))")
接着
for m in pat.finditer(some_string):
m.group(1) # the matched substring
m.span(1) # the slice indices of the match substring
# etc
工作正常。
最好理解(?=(R))
为“在此处匹配一个空字符串,但前提是R
从此处开始,并且如果成功,则将有关R
匹配内容的信息放入第 1 组”。然后finditer()
像匹配空字符串时一样继续进行:它将搜索的开始移动到下一个字符,然后再次尝试(与我第一个答案中的手动循环所做的相同)。
使用它findall()
比较棘手,因为如果R
也包含捕获组,您将获得所有这些组(不能选择和选择,因为您可以使用匹配对象,例如finditer()
返回)。