我用于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,虽然它超出了我的想法。
有没有人知道我可以使用的等效模式,但哪种模式具有良好的性能?
谢谢!
答案 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)*
(*):基本上我的想法是将a*(ba*)*
更改为long_nsdp <- long_nsdp %>% mutate(lnsdp=log(nsdp))
long_nsdp <- long_nsdp %>%
mutate(lnsdp=ifelse(nsdp=="",
log(nsdp+2),lnsdp))