【问题标题】:Count overlapping regex matches once again再次计算重叠的正则表达式匹配
【发布时间】:2012-02-17 07:49:48
【问题描述】:

如何使用 Python 获取 重叠正则表达式 匹配的数量?

我已阅读并尝试了来自 thisthat 和其他一些问题的建议,但没有发现适合我的方案。这里是:

  • 输入示例字符串:akka
  • 搜索模式:a.*k

一个合适的函数应该产生 2 作为匹配的数量,因为有两个可能的结束位置(k 字母)。

模式也可能更复杂,例如a.*k.*a 也应该在akka 中匹配两次(因为中间有两个k)。

【问题讨论】:

  • 我认为您的意思是 -重叠的正则表达式匹配。
  • @jcollado 我想我的意思是重叠。 b.*o 应该在 bboo 中找到 4 次。
  • this answer 有什么问题?
  • 这在 Perl 中很容易做到,只使用一个模式匹配,但我不知道如何让 Python 正常工作。例如:Perl 中的() = "bbboobbooo" =~ /(b.*o)(?{push @all, $1})(*FAIL)/g; printf "got %d matches: %s\n", scalar(@all), "@all"; 将打印出got 21 matches: bbboobbooo bbboobboo bbboobbo bbboo bbbo bboobbooo bboobboo bboobbo bboo bbo boobbooo boobboo boobbo boo bo bbooo bboo bbo booo boo bo。这就是你要找的吗?
  • @tchrist 哇...如果在 perl 中执行起来要简单得多,我将改用该语言。 (反正我几乎都不知道...)

标签: python regex string pattern-matching


【解决方案1】:

我认为您正在寻找的内容可能最好使用像 lepl 这样的解析库来完成:

>>> from lepl import *
>>> parser = Literal('a') + Any()[:] + Literal('k')
>>> parser.config.no_full_first_match()
>>> list(parser.parse_all('akka'))
[['akk'], ['ak']]
>>> parser = Literal('a') + Any()[:] + Literal('k') + Any()[:] + Literal('a')
>>> list(parser.parse_all('akka'))
[['akka'], ['akka']]

我相信parser.parse_all 的输出长度正是您要寻找的。​​p>

请注意,如果您的模式与整个字符串不匹配,您需要使用 parser.config.no_full_first_match() 以避免错误。

编辑:根据@Shamanu4 的评论,我看到你想要从任何位置开始匹配结果,你可以这样做:

>>> text = 'bboo'
>>> parser = Literal('b') + Any()[:] + Literal('o')
>>> parser.config.no_full_first_match()
>>> substrings = [text[i:] for i in range(len(text))]
>>> matches = [list(parser.parse_all(substring)) for substring in substrings]
>>> matches = filter(None, matches) # Remove empty matches
>>> matches = list(itertools.chain.from_iterable(matches)) # Flatten results
>>> matches = list(itertools.chain.from_iterable(matches)) # Flatten results (again)
>>> matches
['bboo', 'bbo', 'boo', 'bo']

【讨论】:

  • 谢谢。与a.*ka.*k.*a 对抗akka 看起来不错,但与b.*o 对抗bboo 失败。
  • @jankes 在这种情况下,parser = Literal('b') + Any()[:] + Literal('o') 我得到:[['bboo'], ['bbo']]。正确的答案是什么?
  • @jcollado 正确答案应该是[['bbo'],['bboo'],['boo'],['bo']]
  • @Shamanu4 感谢您的评论。我已经用您提供的信息更新了答案,现在它适用于示例。
  • 好吧,Python 正则表达式并没有真正为这种高级用户使用正则表达式而设置。如果是这样,单个匹配应该能够找到b.*o"bbboobbooo" 中可以匹配的所有 21 种方式。像 Perl 这样更强大的语言可以在一条语句中做到这一点,但我猜由于 Python 没有将正则表达式集成到语言中,也不允许适当的回溯控制,它又回到了编写另一个库的绘图板上。呃。
【解决方案2】:

是的,它很丑陋且未优化,但它似乎正在工作。这是对所有可能的但独特变体的简单尝试

def myregex(pattern,text,dir=0):
    import re
    m = re.search(pattern, text)
    if m:
        yield m.group(0)
        if len(m.group('suffix')):
            for r in myregex(pattern, "%s%s%s" % (m.group('prefix'),m.group('suffix')[1:],m.group('end')),1):
                yield r
            if dir<1 :
                for r in myregex(pattern, "%s%s%s" % (m.group('prefix'),m.group('suffix')[:-1],m.group('end')),-1):
                    yield r


def myprocess(pattern, text):    
    parts = pattern.split("*")    
    for i in range(0, len(parts)-1 ):
        res=""
        for j in range(0, len(parts) ):
            if j==0:
                res+="(?P<prefix>"
            if j==i:
                res+=")(?P<suffix>"
            res+=parts[j]
            if j==i+1:
                res+=")(?P<end>"
            if j<len(parts)-1:
                if j==i:
                    res+=".*"
                else:
                    res+=".*?"
            else:
                res+=")"
        for r in myregex(res,text):
            yield r

def mycount(pattern, text):
    return set(myprocess(pattern, text))

测试:

>>> mycount('a*b*c','abc')
set(['abc'])
>>> mycount('a*k','akka')
set(['akk', 'ak'])
>>> mycount('b*o','bboo')
set(['bbo', 'bboo', 'bo', 'boo'])
>>> mycount('b*o','bb123oo')
set(['b123o', 'bb123oo', 'bb123o', 'b123oo'])
>>> mycount('b*o','ffbfbfffofoff')
set(['bfbfffofo', 'bfbfffo', 'bfffofo', 'bfffo'])

【讨论】:

  • 非常感谢您抽出宝贵的时间...但是,myprocess 的定义中似乎存在一些缩进错误 - 我不知道如何解决这个问题...
  • @jankes 抱歉,使用code 标记后某些缩进被破坏。现在是正确的。
  • 感谢修复 :) 现在好多了 - 中间或匹配部分后面的多余字母没有效果。但它仍然失败,开头有多余的字符。
  • 在 Python 中真的需要这么多难以置信的代码吗?真的吗?为什么?在 Perl 或 PCRE 中,它只是一个单行。例如,"bbboobbooo" 应该以 21 种可能的方式与 b.*o 匹配。我认为你没有足够好的回溯控制。
  • 我认为它现在可以很好地完成任务。但我已经意识到两件事:1)从@tchrist 的 cmets 来看,Python 不是完成这项任务的最佳语言; 2)我实际上需要所有 - 不仅是独特的匹配。
猜你喜欢
  • 2012-03-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-24
  • 2017-11-10
相关资源
最近更新 更多