【问题标题】:Get start and stop indexes of overlapping matches?获取重叠匹配的开始和停止索引?
【发布时间】:2013-11-15 04:37:55
【问题描述】:

我需要知道下一个正则表达式匹配的开始和结束索引:

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提取了想要的字符串,但是如何获取启动和停止索引呢?

【问题讨论】:

  • 抱歉,我误解了你的问题——起初我并不清楚你所说的重叠匹配是什么意思。但是,有时人们在热心帮助时会犯错误——鉴于此,我认为你的态度是不必要的。 礼貌地解释某人如何误解了你并不难——大多数人在被礼貌地告知后,会变得道歉并寻求做正确的事——有时甚至会经历 这样做比他们开始时没有 被误解,出于弥补错误的愿望更大。粗鲁无礼,您将失去所有考虑。
  • 对不起,如果我粗鲁。我很感激愿意提供帮助。
  • 我看到你已经删除了你的其他 cmets——也许是我误判了你——我很抱歉在发帖之前没有花更多时间来理解你的问题。

标签: python regex


【解决方案1】:

正如@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()返回)。

【讨论】:

  • @Tim Peters 有趣的建议,有两个字符更改。我自己考虑了一下,然后尝试添加 0,因为我认为我匹配了整场比赛!所以在这种情况下,整个组是空的,但子组不是:-)
  • @msh,没错!这就是为什么我会犹豫依赖它的原因:空匹配中存在非空匹配的概念有点尖叫“错误警报!” ;-)
  • @Tim 看起来我在理论上是对的,但在实践中却错了。 .NET 正则表达式做同样的事情 - 即使匹配的总长度为 0,您也可以提取断言中组的长度。
  • @Tomalak,我们在同一条船上 ;-) 现在尝试在 Python-Dev 邮件列表上讨论它。
【解决方案2】:

正则表达式中没有重叠匹配。

要么匹配,要么不匹配。您匹配的任何内容都只能是 one 匹配/子匹配的一部分。

前瞻是短暂的,它们不会增加任何实际计数器。

【讨论】:

  • 您在finditer() 中的.start().end() 索引返回相同的数字,因为正则表达式中没有重叠匹配。但是你去吧,你可能会相信别的东西。
  • 如果您编辑您的答案,我可以撤消反对票,否则反对票将被锁定。
  • 不,我不会。也许下次你在投反对票之前花更多时间。
猜你喜欢
  • 2017-01-18
  • 1970-01-01
  • 1970-01-01
  • 2020-08-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多