我需要知道下一个正则表达式的匹配的开始和结束索引:
pat = re.compile("(?=(ATG(?:(?!TAA|TGA|TAG)\w\w\w)*))")
示例字符串为s='GATGDTATGDTAAAA'
pat.findall(s)
返回所需的匹配['ATGDTATGD', 'ATGDTAAAA']
。如何提取开始和结束索引?
我试过了:
iters = pat.finditer(s)
for it in iters:
print it.start()
print it.end()
但是,it.end()
始终与it.start()
重合,因为我的模式的开始从(?=
开始,因此它不会消耗任何字符串(我需要它来捕获重叠匹配)。显然pat.findall
提取了所需的字符串,但是如何获取开始和停止索引?
答案 0 :(得分:5)
正如@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
)捕获组的开始和结束。通过不传递参数,你得到整个匹配的开始和结束 - 但是当然匹配的断言总是匹配一个空字符串(因此start和end是相等的)。
我说这是危险的生活,因为一个捕获组里面的语义一个断言(无论是向前看还是向后看,正面还是负面......)都充其量是模糊的。很难说你是否在这里偶然发现了一个错误(或实施意外)!可爱: - )
编辑:经过一夜的睡眠和对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()
返回)。
答案 1 :(得分:4)
正则表达式中没有重叠匹配。
要么你匹配某些东西,要么你不匹配。您匹配的任何内容只能是一个匹配/子匹配的一部分。
前瞻是短暂的,他们不会增加任何真正的反击。