检测正则表达式是否呈指数级

时间:2010-07-31 09:53:29

标签: regex algorithm complexity-theory

这个article表明在回溯时有一些正则表达式为O(2 ^ n)。 示例是(x+x+)+y。 当尝试匹配像xxxx ...这样的字符串时,它会回溯一段时间,然后才发现它无法匹配。

有没有办法检测这种正则表达式?

感谢

4 个答案:

答案 0 :(得分:9)

如果你的正则表达式引擎暴露了(x + x +)+ y的运行时指数行为,那么已经 ,因为DFA或NFA可以在线性时间内识别出这种模式:

echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" | egrep "(x+x+)+y"
echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxy" | egrep "(x+x+)+y"

立即回答。

事实上,只有少数情况(如反向引用)确实需要回溯(主要是因为具有反向引用的正则表达式不再语言理论意义上的正则表达式)。只有在给出这些极端情况时,一个有能力的实现应该切换到回溯。

公平地说,DFA也有一个黑暗的一面,因为一些正则表达式具有指数大小要求,但是尺寸约束比时间约束更容易执行,并且巨大的DFA在输入上运行线性,所以它比一个更好的讨价还价几个X的小后座窒息。

你应该真的阅读有关regexp实施(以及回溯的病态行为)的Russ Cox优秀文章系列:http://swtch.com/~rsc/regexp/

回答有关可判定性的问题:你不能。因为regexpr没有一个回溯。每个实现都有自己的策略来处理某些情况下算法的指数增长,而不涉及其他情况。一条规则可能适合这里,也可能是灾难性的。

更新:

例如,一个实现可以包含一个优化器,它可以在执行它们之前使用代数转换来简化正则表达式:(x+x+)+yxxx*y相同,这对于任何回溯都不应该是一个问题。但是同样的优化器不会识别下一个表达式,问题又出现了。在这里,有人描述了如何制作一个愚弄Perl优化器的regexpr:

http://perlgeek.de/blog-en/perl-tips/in-search-of-an-exponetial-regexp.html

答案 1 :(得分:2)

不,我不这么认为,但您可以使用这些指南:

  • 如果它包含两个在高端开放的量词,并且它们是嵌套的,那么可能 O(2 ^ n)。
  • 如果它不包含两个这样的量词,那么我认为它不能是O(2 ^ n)。

导致此问题的量词包括:*+{k,}

另请注意,评估正则表达式的最坏情况复杂性可能与典型字符串的复杂性非常不同,复杂性取决于特定的正则表达式引擎。

答案 2 :(得分:1)

任何没有反向引用的正则表达式都可以在线性时间内匹配,尽管现实世界中的许多正则表达式引擎都没有这样做(至少许多插入编程语言运行时环境的正则表达式引擎支持反向引用,并且不要当没有反向引用时,不要切换到更高效的执行模型。

没有简单的方法可以找出带反向引用的正则表达式消耗的时间。

答案 3 :(得分:1)

您可以使用正则表达式解析器来检测和拒绝嵌套重复,该解析器对应于star height的1.我刚刚使用npm的正则表达式解析器编写a module to compute and reject start heights of >1

$ node safe.js '(x+x+)+y'
false
$ node safe.js '(beep|boop)*'
true
$ node safe.js '(a+){10}'
false
$ node safe.js '\blocation\s*:[^:\n]+\b(Oakland|San Francisco)\b'
true