首页 文章

再次计算重叠的正则表达式匹配

提问于
浏览
7

如何使用Python获取 overlapping regex 匹配的数量?

我已经阅读并尝试了thisthat和其他一些问题的建议,但发现没有一个可以用于我的方案 . 这里是:

  • 输入示例字符串: akka

  • 搜索模式: a.*k

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

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

2 回答

  • 3

    是的,这是丑陋的,未经优化但似乎有效 . 这是对所有可能的 but unique 变体的简单尝试

    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'])
    
  • 2

    我认为你正在寻找的东西最好用一个像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 的输出长度是你正在寻找的 .

    请注意,如果模式与整个字符串不匹配,则需要使用 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']
    

相关问题