【问题标题】:Complexity of Regex substitution正则表达式替换的复杂性
【发布时间】:2008-08-22 03:02:34
【问题描述】:

我在任何地方都没有得到答案。正则表达式匹配和替换的运行时复杂度是多少?

编辑:我在 python 中工作。但想大致了解最流行的语言/工具(java、perl、sed)。

【问题讨论】:

    标签: regex complexity-theory


    【解决方案1】:

    从纯粹的理论立场:

    我熟悉的实现是构建一个确定性有限自动机来识别正则表达式。这是在 O(2^m) 中完成的,m 是正则表达式的大小,使用标准算法。一旦构建完成,通过它运行一个字符串在字符串长度上是线性的 - O(n),n 是字符串长度。在字符串中找到的匹配项的替换应该是常数时间。

    所以总的来说,我想 O(2^m + n)。

    【讨论】:

    • 根据某些量词的需要考虑回溯时,复杂性是否仍然是线性的?
    • 我对“这是在 O(2^m) 中完成,m 是正则表达式的大小,使用标准算法”的证明感兴趣。你是怎么想到的?
    • 极端情况下的运算次数有调和级数吗?
    • O(2^m) 其实太悲观了;您无需创建 DFA 即可运行它 :)
    • 这里是包含事实证明的文章的链接:A. V. Aho,“在字符串中查找模式的算法”,《理论计算机科学手册》,卷。 A. Algorit,Elsevier,1990,第 255-300 页。 full text
    【解决方案2】:

    其他可能感兴趣的理论信息。

    为清楚起见,假设正则表达式的标准定义

    http://en.wikipedia.org/wiki/Regular_language

    来自形式语言理论。实际上,这意味着唯一的建筑 材料是字母符号,连接运算符,交替和 Kleene 闭包,以及单位和零常数(出现在 群论原因)。一般来说,不要超载这个术语是个好主意 尽管脚本语言的日常实践导致 模棱两可。

    有一个 NFA 结构可以解决正则的匹配问题 表达式 r 和输入文本 t 在 O(|r| |t|) 时间和 O(|r|) 空间中,其中 |-|是长度函数。 Myers进一步改进了这个算法

    http://doi.acm.org/10.1145/128749.128755

    通过使用自动机节点列表和四俄罗斯人范式,时间和空间复杂度 O(|r| |t| / log |t|)。这个范式似乎是以四个俄罗斯人的名字命名的,他们写了一篇开创性的论文 在线的。然而,范式在这些计算生物学中得到了说明 讲义

    http://lyle.smu.edu/~saad/courses/cse8354/lectures/lecture5.pdf

    我觉得用数字命名范式很有趣 作者的国籍而不是他们的姓氏。

    添加反向引用的正则表达式的匹配问题是 NP-complete,由 Aho 证明

    http://portal.acm.org/citation.cfm?id=114877

    通过减少顶点覆盖问题,这是一个经典的 NP 完全问题。

    为了确定性地匹配正则表达式和反向引用,我们可以 使用回溯(与 Perl 正则表达式引擎不同)来跟踪 可以分配给变量的输入文本 t 的可能子词 河。只有 O(|t|^2) 个子词可以分配给任何一个变量 在河如果r中有n个变量,那么有O(|t|^2n)个可能 作业。一旦将子字符串分配给变量是固定的, 问题简化为普通的正则表达式匹配。因此 匹配正则表达式与反向引用的最坏情况复杂度是 O(|t|^2n)。

    但是请注意,带有反向引用的正则表达式还没有 功能齐全的正则表达式。

    例如,将“无关”符号与其他符号区分开来 运营商。有几种多项式算法决定一组 模式匹配输入文本。比如库切罗夫和鲁西诺维奇

    http://dx.doi.org/10.1007/3-540-60044-2_46

    将模式定义为一个单词 w_1@w_2@...@w_n 其中每个 w_i 是一个单词(不是正则表达式),而“@”是一个不包含在任何一个中的可变长度“无关”符号w_i。他们推导出一个 O((|t| + |P|) log |P|) 算法,用于将一组模式 P 与输入文本 t 进行匹配,其中 |t|是文本的长度,|P|是P中所有单词的长度。

    了解这些复杂性度量如何组合以及什么是有趣的 是正则表达式匹配问题的复杂度度量 反向引用、“不关心”和其他有趣的实用功能 正则表达式。

    唉,我对 Python 只字未提... :)

    【讨论】:

      【解决方案3】:

      取决于您通过正则表达式定义的内容。如果允许连接、替代和 Kleene-star 运算符,则时间实际上可以是 O(m*n+m),其中 m 是正则表达式的大小,n 是字符串的长度。你可以通过构造一个 NFA(在 m 中是线性的),然后通过维护你所处的状态集并为每个输入字母更新它(在 O(m) 中)来模拟它。

      使正则表达式解析变得困难的事情:

      • 括号和反向引用:使用上述算法进行捕获仍然可以,尽管它会使复杂性更高,因此可能不可行。反向引用提高了正则表达式的识别能力,它的难度很好
      • 正向前瞻:只是交集的别称,将上述算法的复杂度提高到O(m^2+n)
      • 负前瞻:构建自动机的灾难(O(2^m),可能是 PSPACE-complete)。但是应该仍然可以使用O(n^2*m) 之类的动态算法来解决

      请注意,通过具体实施,事情可能会变得更好或更糟。根据经验,简单的特征应该足够快,并且明确的(例如,不像a*a*)正则表达式更好。

      【讨论】:

        【解决方案4】:

        深入研究theprise的答案,对于自动机的构造,O(2^m) 是最坏的情况,尽管它实际上取决于正则表达式的形式(对于一个匹配单词的非常简单的表达式,它是在 O(m) 中,例如使用 Knuth-Morris-Pratt algorithm)。

        【讨论】:

          【解决方案5】:

          取决于实施。什么语言/图书馆/课程?可能有一个最好的情况,但它会非常具体到实现中的功能数量。

          【讨论】:

            【解决方案6】:

            您可以通过构建非确定性有限自动机而不是 DFA 来以空间换取速度。这可以在线性时间内遍历。当然,在最坏的情况下,这可能需要 O(2^m) 空间。我希望这种权衡是值得的。

            【讨论】:

              【解决方案7】:

              如果您在匹配和替换之后,这意味着分组和反向引用。

              这是一个 perl 示例,其中可以使用分组和反向引用来解决 NP 完全问题: http://perl.plover.com/NPC/NPC-3SAT.html

              这(加上一些其他的理论花絮)意味着使用正则表达式进行匹配和替换是 NP 完全的。

              请注意,这与正则表达式的正式定义不同 - 它没有分组的概念 - 并且在多项式时间内匹配,如其他答案所述。

              【讨论】:

              • 恐怕我不明白你所说的“解决一个NP完全问题”是什么意思。由于其 NP 完全性,没有有效的(多项式时间)算法来计算 3-CNF-SAT 的实例。人们需要这样一种算法来解决问题。可以使用正则表达式对 3-CNF-SAT 进行编码这一事实并不意味着正则表达式可以解决 3-CNF-SAT,因为没有用于计算正则表达式的多项式时间算法。
              • 我最初并没有提到多项式时间 - 我认为我的回答暗示正则表达式匹配和替换是在 NP 中,尽管经过反思,我写它的方式并不那么清楚。我已经清理了我的答案,希望它能澄清一些事情。感谢您的反馈。
              【解决方案8】:

              在 python 的 re 库中,即使编译了正则表达式,在某些情况下复杂性仍然是指数级的(以字符串长度计),因为它不是基于 DFA 构建的。一些参考hereherehere

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2015-02-21
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多