3

让我们考虑 C# 中的以下两行(使用框架 .NET 3.5)

Regex regex = new Regex(@"^((E|e)t )?(M|m)oi (?<NewName>[A-Za-z]\.?\w*((\-|\s)?[A-Za-z]?\w{1,})+)$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
Match m = regex.Match("moi aussi jaimerai etre un ordinateur pour pas m'énnerver ");

(对不起,这是一个法语节目 :))

当它们被执行时,进程会卡在Match()方法中并且永远不会退出。我想正则表达式模式中的空白存在一些问题,但我想做的不是改变模式(实际上它是由我的工具的最终用户在程序之外设置的)但能够停止该过程(例如超时)。

有人知道这是否是 .NET 正则表达式的众所周知的问题,是否有一种简单的方法可以解决它,或者我是否必须线程化这些行并在需要时中止它们(当然我不想这样做)。

4

5 回答 5

4

如果我在 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的作者,询问检测这种情况需要什么。

于 2009-04-29T12:21:59.473 回答
1

我认为您应该简单地在单独的线程上启动正则表达式匹配,并在达到某个最大时间限制时允许中止它。

于 2009-04-29T12:35:54.743 回答
-1

通常,正则表达式可能需要比您预期的更长的时间。您应该使用 Regulator 之类的工具来试验正则表达式。

于 2009-04-29T12:00:22.130 回答
-1

问题是您在正则表达式中嵌套了“循环”,这使得它非常低效(因此由于表达式的复杂性,它基本上需要很长时间)。

如果你说你想匹配什么,我可以尝试找出一个更有效的正则表达式。

于 2009-04-29T12:11:13.553 回答
-1

在我看来,正则表达式匹配呈指数增长。请参阅BCL 博客

最好的解决方案是在正则表达式上设置一个超时,不要搞乱线程。

请参阅此处如何使用 timeout 去除字符串

于 2013-11-07T14:11:53.370 回答