在阅读了RE / NFA和DFA之后,似乎找到一个字符串中的子字符串实际上可以使用RE而不是强力O(mn)找到渐进式更快。我的理由是DFA实际上会保持状态并避免不止一次地处理“haystack”中的每个字符。因此,如果使用正则表达式,长字符串中的搜索实际上可能会快得多。
当然,这仅适用于从NFA转换为DFA的RE匹配器。
在使用RE而不是强力匹配器时,有没有人在现实生活中经历过更好的弦乐匹配表现?
答案 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更好。