可怜的Python'表现'的情况

时间:2016-03-09 11:09:16

标签: python regex

我用于autocompletion in lua的Sublime包使用了Python的're'模块,但是一个正则表达式导致了大幅减速。这是一个最小的例子:

import re
rx = re.compile(r"\bfunction(?:\s+[a-zA-Z0-9._]*)?\(((?:[a-zA-Z_][a-zA-Z0-9_]*|\.\.\.|,\s*)*)\)")
rx.match('function f(aaaaaaa, bbbbbbbb, cccccccc, ddddddd eeeeee)')  # Very slow
rx.match('function f(aaaaaaa, bbbbbbbb, cccccccc, ddddddd, eeeeee)')  # Adding a comma between the last function arguments in the string fixes it.

我对正则表达式调试没有深度,但this seems relevant,虽然它超出了我的想法。

有没有人知道我可以使用的等效模式,但哪种模式具有良好的性能?

谢谢!

2 个答案:

答案 0 :(得分:1)

问题是该模式包含* - 量化的*量词:(?:[a-zA-Z_][a-zA-Z0-9_]*|\.\.\.|,\s*)*。必须避免使用这些嵌套量词。如果您无法将备选方案重新安排到后续(可选)组中,则占有量词或原子组通常会有所帮助。

Python re不支持占有量词,也不支持原子组。

但是,您可以使用具有模拟原子组的版本:

\bfunction(?:\s+[a-zA-Z0-9._]*)?\(((?:(?=([a-zA-Z_][a-zA-Z0-9_]*))\2|\.\.\.|,\s*)*)\)
                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^                  

[a-zA-Z_][a-zA-Z0-9_]*子模式放置在一个带有正向后视的捕获组中。 (?=([a-zA-Z_][a-zA-Z0-9_]*))\2[a-zA-Z_][a-zA-Z0-9_]*几乎相同(因为它匹配相同的东西),但它使子模式成为原子(因此,在其他类型中它看起来像[a-zA-Z_][a-zA-Z0-9_]*+(?>[a-zA-Z_][a-zA-Z0-9_]*+) )。 "原子" \2反向引用的性质不会让回溯超出[a-zA-Z_][a-zA-Z0-9_]*

请参阅regex demo

此外,您可能需要re.search,因为您的模式以\b开头。请注意,re.match只能在字符串的开头找到匹配项(=它锚定在字符串的开头)。

答案 1 :(得分:1)

主要问题来自嵌套量词re.compile(r'''\bfunction\b \s*[a-zA-Z0-9._]* \( ( (?: (?:[a-zA-Z_][a-zA-Z0-9_]*|\.\.\.) (?: ,\s* (?:[a-zA-Z_][a-zA-Z0-9_]*|\.\.\.) )* )? ) \)''', re.VERBOSE) ,当下面的子模式失败时,它可能导致灾难性的回溯。

如果您展开 * 此子模式,则可以避免此问题。我使用了详细模式使其更具可读性:

(a*|b)*

demo

(*):基本上我的想法是将a*(ba*)*更改为long_nsdp <- long_nsdp %>% mutate(lnsdp=log(nsdp)) long_nsdp <- long_nsdp %>% mutate(lnsdp=ifelse(nsdp=="", log(nsdp+2),lnsdp))