【问题标题】:Find all (including overlapping) substrings matching a regular expression in Python在 Python 中查找与正则表达式匹配的所有(包括重叠的)子字符串
【发布时间】:2021-08-20 07:40:49
【问题描述】:

我需要在字符串中找到与正则表达式匹配的所有子字符串的位置。例如,如果字符串为abbba,正则表达式为(b|bb)(?=a),则结果应为[(2, 4), (3, 4)]

我想出的是

def get_ranges(pattern: str, string: str) -> list[tuple[int, int]]:
    n = len(string)
    return [(start, end) for start in range(n + 1) for end in range(start, n + 1)
            if re.fullmatch(f'.{{{start}}}({pattern}).{{{n - end}}}', string)]

但这往往会执行得非常缓慢,尤其是考虑到它不允许使用预编译的正则表达式。有没有更有效的方法来解决这个问题?

【问题讨论】:

    标签: python regex performance


    【解决方案1】:

    首先我认为你应该使用for end in range(start, n + 1)。对于 end 变量,我看不出有任何理由从 0 开始每次迭代。只需进行此编辑,即可执行此代码

    for i in range(300000):
        get_ranges(r"(b|bb)(?=a)", "abbba")
    

    我从 9.67 秒到 6.01 秒。

    【讨论】:

    • 很好,谢谢。我已经更新了我的原始代码。然而,我认为这并不能解决问题。
    【解决方案2】:

    您可能想尝试稍微不同的正则表达式 - (b{1,2})(?=a),它应该会稍微快一些。

    其次,你可以编译模式并使用它通过切割字符串而不是正则表达式来编译:

    pattern = re.compile('(b{1,2})(?=a)')
    def get_ranges(pattern: str, string: str):
    
    result = []
    start, end = 0, len(string)
    match = pattern.search(string)
    while match is not None and start < end:
        result.append((match.start(0)+start, match.end(0)+start))
        start += match.start(0) + 1
        match = pattern.search(string[start:])
    
    return result
    

    你也可以yield而不是在返回之前完整地构造result

    比较时间(每 100 万高管):

    • 原始:38.42 秒
    • 高于:2.14 秒(17.95 倍加速)
    • yield 版本:0.2914 秒(131.85 倍加速)

    【讨论】:

    • 不幸的是,这在一般情况下不起作用,因为多个匹配的子字符串可以从一个位置开始。此外,删除字符串的前缀会干扰lookbehinds(我也需要使用它)。因此,例如,模式 (?&lt;=a)(b{1,2}) 将产生 [(1, 3)] 而不是预期的 [(1, 2), (1, 3)],并且似乎没有快速解决方法。
    • 好吧,您没有在问题中指定这一点,是吗?但是,如果您需要lookbehinds,那么它确实不适用于您的情况。
    • 这似乎只相当于return [m.span(1) for m in re.finditer(f'(?=({pattern}))', string)]
    • @sophros 这不仅仅是关于lookbehinds。简单的b{1,2},与字符串bb 匹配,将返回[(0, 2), (1, 2)],而不是预期的[(0, 1), (0, 2), (1, 2)]
    • 同意。对于具有可选贪婪匹配的正则表达式,该解决方案不是最佳的。
    猜你喜欢
    • 2012-07-03
    • 2015-06-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-15
    相关资源
    最近更新 更多