【问题标题】:substring match faster with regular expression?使用正则表达式更快地匹配子字符串?
【发布时间】:2011-03-19 05:11:58
【问题描述】:

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

当然,这仅对从 NFA 转换为 DFA 的 RE 匹配器有效。

有没有人在现实生活中使用 RE 而不是暴力匹配器时体验到更好的字符串匹配性能?

【问题讨论】:

    标签: regex string regular-language


    【解决方案1】:

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

    这是一种无处不在的权衡。也就是说,解决方案越灵活、功能越丰富,其性能就越差。

    【讨论】:

      【解决方案2】:

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

      就我个人而言,我没有对两者进行任何形式的性能比较。但是,根据我的经验,我从来没有遇到过蛮力查找和替换的性能问题,而我不得不多次处理 RE 性能瓶颈。

      【讨论】:

      • 是的,同意。我更关心将子字符串与这样的 RE 匹配 (/someString/)。是的,它必须在 C 中,因为我猜这是 RE 引擎转换为 DFA 的唯一语言。
      【解决方案3】:

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

      由于许多语言中的正则表达式不仅用于匹配,而且还提供组捕获和反向引用的可能性,所以几乎所有实现在执行从给定正则表达式构建的 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。

      【讨论】:

      • 博耶-摩尔是O(n);它永远不需要超过3n 比较。更简单的 Boyer-Moore-Horspool 最多需要 mn,但这不是“相同”的算法。
      猜你喜欢
      • 2015-02-04
      • 1970-01-01
      • 2011-11-08
      • 1970-01-01
      • 2013-04-13
      • 2022-07-11
      • 2014-11-26
      • 2022-01-17
      • 1970-01-01
      相关资源
      最近更新 更多