子串与正则表达式匹配得更快?

时间:2010-07-21 20:05:42

标签: regex string regular-language

在阅读了RE / NFA和DFA之后,似乎找到一个字符串中的子字符串实际上可以使用RE而不是强力O(mn)找到渐进式更快。我的理由是DFA实际上会保持状态并避免不止一次地处理“haystack”中的每个字符。因此,如果使用正则表达式,长字符串中的搜索实际上可能会快得多。

当然,这仅适用于从NFA转换为DFA的RE匹配器。

在使用RE而不是强力匹配器时,有没有人在现实生活中经历过更好的弦乐匹配表现?

3 个答案:

答案 0 :(得分:3)

在实践中使用的大多数正则表达式是PCRE(Perl兼容的正则表达式),它比常规语言更宽,因此不能用常规语法表达。 PCRE具有正/负前瞻/后瞻断言甚至递归的功能,因此解析可能需要多次处理某些字符。当然,这一切都归结为特定的RE实现:如果表达式保持在常规语法的范围内,它是否被优化。

就个人而言,我没有在两者之间进行任何性能比较。但是,根据我的经验,我从来没有遇到过暴力查找和替换的性能问题,而我不得不在不止一次的情况下处理RE性能瓶颈。

答案 1 :(得分:1)

如果你查看大多数语言的文档,它会提到如果你不需要强大的正则表达式,你应该使用非正则表达式的性能原因...例如:http://www.php.net/manual/en/function.preg-split.php状态:“如果你不喜欢不需要正则表达式的强大功能,你可以选择更快(尽管更简单)的替代方案,比如explode()或str_split()。“

这是一种存在于任何地方的权衡。这是一种更灵活,功能更丰富的解决方案,其性能越差。

答案 2 :(得分:1)

首先,我建议您阅读有关几种语言的正则表达式内部的文章:Regular Expression Matching Can Be Simple And Fast

由于许多语言中的regexp不仅仅用于匹配,而且还提供了组捕获和反向引用的可能性,因此在执行从给定regexp构建的NFA时,几乎所有实现都使用所谓的“回溯”。而这种实现具有指数时间复杂度(在最坏的情况下)。

可以通过DFA进行RE实施(使用群组捕获),但它有一个开销(参见Laurikari的论文NFAs with Tagged Transitions, their Conversion to Deterministic Automata and Application to Regular Expressions)。

对于简单的子字符串搜索,您可以使用Knuth-Morris-Pratt算法,该算法构建DFA以搜索子字符串,并且它具有最佳的O(len(s))复杂度。但它也有开销,如果你在现实世界的单词和短语(不那么重复)上对这个优化算法测试天真的方法(O(nm)),你会发现天真的方法平均更好。

对于精确的子字符串搜索,您还可以尝试Boyer–Moore算法,其具有O(mn)最坏情况复杂度,但在实际数据上平均比KMP更好。