Regex 为什么正则表达式可以有指数级的运行时间?

Regex 为什么正则表达式可以有指数级的运行时间?,regex,Regex,可以编写在某些情况下需要指数级运行时间的正则表达式。这样的例子是(aa | aa)*。如果输入的as为奇数,则需要指数级的运行时间 这很容易测试。如果输入仅包含as且长度为51,则正则表达式需要几秒钟来计算(在我的机器上)。相反,如果输入长度为52,则其计算时间不明显(我使用JavaRE的内置正则表达式解析器对此进行了测试) 我已经编写了一个正则表达式解析器来查找这种行为的原因,但是我没有找到它。我的解析器可以基于正则表达式构建或。在这之后,它可以将NFA转换为a。为此,它使用 当我解析上面提到

可以编写在某些情况下需要指数级运行时间的正则表达式。这样的例子是
(aa | aa)*
。如果输入的
a
s为奇数,则需要指数级的运行时间

这很容易测试。如果输入仅包含
a
s且长度为51,则正则表达式需要几秒钟来计算(在我的机器上)。相反,如果输入长度为52,则其计算时间不明显(我使用JavaRE的内置正则表达式解析器对此进行了测试)

我已经编写了一个正则表达式解析器来查找这种行为的原因,但是我没有找到它。我的解析器可以基于正则表达式构建或。在这之后,它可以将NFA转换为a。为此,它使用

当我解析上面提到的Rgex时,解析器创建了一个具有7个状态的NFA——在转换之后,DFA中只剩下3个状态。DFA代表更合理的Regex
(aa)*
,可以非常快速地解析


因此,我不明白为什么会有这么慢的解析器。这是什么原因?他们不把NFA翻译成DFA吗?如果是,原因为何?它们计算如此之慢的技术原因是什么?

符合这一点的正则表达式可以在线性时间内计算,因为它们有相应的有限自动机。它们仅由括号、可选|(有时称为sum)、Kleene星形*和串联构成

例如,通过添加反向引用来扩展正则表达式,甚至可以得到NP完全正则表达式。 在这里你可以发现识别非素数


我猜想,即使在简单的情况下,这样一个扩展的实现也会有非线性匹配时间

我用Perl做了一个快速的实验,您的正则表达式对奇数和偶数的“a”的计算速度相同。

(,)

正则表达式匹配可以简单而快速,使用基于有限自动机的技术,这种技术已经为数十年所知。相比之下,Perl、PCRE、Python、Ruby、Java和许多其他语言都有基于递归回溯的正则表达式实现,这些实现很简单,但速度非常慢。除了回溯引用,慢速回溯实现提供的特性可以由基于自动机的实现以更快、更一致的速度提供

在很大程度上,这归结于“正则”表达式(如反向引用)中非正则特性的激增,以及大多数程序员(继续)对不包含此类特性的正则表达式有更好的替代方案(其中很多)的无知

在20世纪80年代初编写文本编辑器sam时,Rob Pike编写了一个新的正则表达式实现,Dave Presotto将其提取到第八版中出现的库中。派克的实现将子匹配跟踪纳入了一个高效的NFA模拟中,但与第八版源代码的其他部分一样,并未广泛分发。派克自己并没有意识到他的技术有什么新东西。Henry Spencer从头开始重新实现了第八版库接口,但使用了回溯,并将其实现发布到公共领域。它得到了广泛的应用,最终成为前面提到的慢速正则表达式实现的基础:Perl、PCRE、Python等等。(在他的辩护中,斯宾塞知道例程可能很慢,他不知道还有更高效的算法存在。他甚至在文档中警告说,“许多用户发现速度完全足够,尽管用此代码替换egrep的内部将是一个错误。”)Pike的正则表达式实现,扩展到支持Unicode,在1992年底sam免费提供,但是特别高效的正则表达式搜索算法没有被注意到


可以在常用库中构造触发病理性能案例的REs,而无需借助非常规功能,例如
(.*)(.*)(.*)(.*)(.*)(.*)(.*)(.*)
。请参阅我的答案中的文章。“这样一个扩展的实现即使在简单的情况下也会有非线性匹配时间。”只有在实现者没有注意的情况下。检查re是否包含反向引用只需要线性时间。在这一点上,您可以决定将其放入正则表达式匹配器或非正则“正则表达式”匹配器。关于您的基准测试-多年来,Perl一直在以内存为代价记忆其回溯,导致此类匹配的线性时间(并且在一定规模下,它会切换回指数CPU)。我想这就是你看到的。(或者它最终修复了解析器?很可能我错过了新闻。)好吧,说识别素数是NP完全是错误的。搜索“素数在P中”。在我真正读了这篇文章之后,它就更错了。给定N,素数在P中意味着需要对数(N)的多项式来检查N是否为素数。你提到的文章需要O(N)来检查RE是否是线性时间。你应该再次学习计算理论。这不是我所期望的答案——像“实现基于低效算法”这样的理由不是很令人满意。不过,非常感谢你的这篇文章。这个答案是否意味着大多数正则表达式引擎并不是基于每门计算理论课程中所教授的快速简单的有限状态自动机?那是因为大多数人在80/90年代都不知道他们?我发现很难相信——计算理论不是从时间的黎明起就成为每门计算机科学课程的一部分吗?@BlueRaja:你是否否认大多数(按市场份额)正则表达式实现都使用回溯实现?如果你不相信我的摘录,你可以,比如,读文章。或者大多数项目的源代码。或者