我在Formal Languages中有一些背景知识,最近我发现Java和其他语言使用的是扩展常规语言。由于我的背景,当我为Pattern调用编译时,我总是假设使用Java等语言,它在后台生成了DFA或传感器。结果,无论我的正则表达式有多丑,无论我的正则表达式,Pattern.matches或类似方法在线性时间内运行多长时间,我总是假设。但这个假设似乎是incorrect。
我读过的post似乎暗示一些正则表达式确实在线性时间内运行,但我并不完全相信或信任一个人。
我最终会编写自己的Java Formal Regular Expression库(我发现现有的只有GNU GPL许可证),但与此同时我对Java / C#regexs的时间复杂性有几个疑问。想要确保我读到的内容elsewhere是正确的。
问题:
我进行文本分析,发现Java正则表达不是DFA真的是一种贬低。
答案 0 :(得分:6)
由于我的背景,我一直假设使用Java这样的语言,当我调用编译模式时,它会在后台生成DFA或传感器。
这种信念在学术界很常见。实际上,正则表达式编译不会生成DFA然后执行它。我只有少量的经验;我在20世纪90年代微软的JavaScript实现中简要介绍了正则表达式编译系统。我们选择将“常规”表达式编译成一个简单的特定于域的字节码语言,然后为该语言构建一个解释器。
正如您所注意到的,这可能导致重复回溯在输入长度中具有指数级不良时间行为的情况,但编译状态的构造在表达式的大小上基本上是线性的。
所以让我用另外两个问题来反驳你的问题 - 我注意到这些是真正的问题,而不是修辞。
1)每个实际正则表达式对应于一个NDFA,假设n个状态。相应的DFA可能需要叠加最多2个 n 状态。那么是什么阻止了在病理情况下构建DFA所呈现的指数呢?运行时在输入中可能是线性的,但如果运行时在模式大小中是指数的,那么基本上你只是将一个非线性换成另一个非线性。
2)如今所谓的“常规”表达并不是那种;他们可以做括号匹配。它们对应于下推自动机,而不是非确定性有限自动机。是否有线性算法为“常规”表达式构造相应的下推自动机?
答案 1 :(得分:2)
正则表达式以多种语言实现为NFA以支持回溯(参见http://msdn.microsoft.com/en-us/library/e347654k(v=vs.110).aspx)。由于回溯,您可以构造在某些字符串上具有可怕性能的正则表达式(请参阅http://www.regular-expressions.info/catastrophic.html)
至于分析正则表达式来确定它们的表现,我怀疑总的来说有一个很好的方法。您可以在第二个链接的示例中查找警告标记,例如复合回溯,但即使在某些情况下也可能难以正确检测。
答案 2 :(得分:1)
Java的正则表达式实现使用NFA方法。 这是link,可以清楚地解释它。
基本上,写得不好但仍然正确的正则表达式会导致引擎性能不佳。
例如,给定表达式(a+a+)+b
和字符串aaaaaaaaaaaaaaa
。
可能需要一段时间(取决于您的机器,从几秒钟到几分钟)才能确定没有匹配。
NFA最糟糕的表现是几乎匹配的情况(举例)。因为表达式会强制引擎探索每条路径(有很多回溯)来确定不匹配。