如果我在 Regexbuddy 中输入表达式,它会显示以下消息
由于正则表达式太复杂,匹配尝试被提前中止。您计划使用它的正则表达式引擎可能根本无法处理它并崩溃。在帮助文件中查找“灾难性回溯”以了解如何避免这种情况。
查找灾难性回溯给出以下解释
失控的正则表达式:灾难性回溯
考虑正则表达式 (x+x+)+y。在你惊恐地尖叫并说这个人为的例子应该写成 xx+y 以完全匹配没有那些可怕的嵌套量词之前:假设每个“x”代表更复杂的东西,某些字符串被两个“x”匹配. 请参阅下面有关 HTML 文件的部分以获取真实示例。
让我们看看当您将此正则表达式应用于 xxxxxxxxxxy 时会发生什么。第一个 x+ 将匹配所有 10 个 x 字符。第二个 x+ 失败。第一个 x+ 然后回溯到 9 个匹配,第二个拾取剩余的 x。该组现已匹配一次。该组重复,但在第一个 x+ 处失败。由于重复一次就足够了,因此小组匹配。y 匹配 y 并找到整体匹配。正则表达式被声明为有效,代码被发送给客户,他的计算机爆炸了。几乎。
当主题字符串中缺少 y 时,上述正则表达式变得难看。当 y 失败时,正则表达式引擎回溯。该组有一个可以回溯到的迭代。第二个 x+ 只匹配一个 x,所以它不能回溯。但是第一个 x+ 可以放弃一个 x。第二个 x+ 立即匹配 xx。该组再次进行一次迭代,下一次失败,并且 y 失败。再次回溯,第二个 x+ 现在有一个回溯位置,减少自身以匹配 x。该小组尝试第二次迭代。第一个 x+ 匹配,但第二个被卡在字符串的末尾。再次回溯,该组第一次迭代中的第一个 x+ 将自身减少到 7 个字符。第二个 x+ 匹配 xxx。如果 y 失败,则第二个 x+ 减少为 xx,然后是 x。现在,该组可以匹配第二次迭代,每个 x+ 一个 x。但是这个 (7,1),(1,1) 组合也失败了。所以它去 (6,4) 然后是 (6,2)(1,1) 然后是 (6,1),(2,1) 然后是 (6,1),(1,2) 然后我认为你开始得到漂移。
如果您在 RegexBuddy 的调试器中对 10x 字符串尝试此正则表达式,则需要 2558 步才能确定最后的 y 缺失。对于 11x 字符串,它需要 5118 步。对于 12,它需要 10238 步。显然,我们这里的指数复杂度为 O(2^n)。在 21 倍时,调试器以 280 万步退出,诊断出灾难性回溯的不良情况。
RegexBuddy 是宽容的,因为它检测到它正在转圈,并中止匹配尝试。其他正则表达式引擎(如 .NET)将永远运行,而其他正则表达式引擎将因堆栈溢出而崩溃(如 Perl,版本 5.10 之前)。堆栈溢出在 Windows 上尤其令人讨厌,因为它们往往会使您的应用程序消失得无影无踪。如果您运行允许用户提供自己的正则表达式的 Web 服务,请务必小心。很少有正则表达式经验的人在提出指数级复杂的正则表达式方面有着惊人的技巧。
我假设您将不得不在代码中处理它。我建议你联系Regexbuddy的作者,询问检测这种情况需要什么。