正如@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
代码进行两个字符的更改:
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()
返回的匹配对象那样挑选和选择)。