如何处理来自用户提交的正则表达式的无休止匹配

时间:2009-04-29 11:52:13

标签: c# .net regex user-input

让我们考虑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正则表达式的众所周知的问题,如果有一种简单的方法可以解决它,或者我必须线程化这些行并在需要时中止它们(我绝对不喜欢)这样做。)

5 个答案:

答案 0 :(得分:4)

如果我在Regexbuddy中输入表达式,则会显示以下消息

  

比赛尝试提早中止   因为正则表达式也是如此   复杂。你计划的正则表达式引擎   使用它可能无法处理   它根本就崩溃了。抬头   “灾难性的回溯”   帮助文件,以了解如何避免这种情况   情况。

查找灾难性回溯会给出以下解释

  

失控正则表达式:灾难性回溯
  考虑正则表达式(x + x +)+ y。   在你惊恐地尖叫之前说   这个人为的例子应该是   写成xx + y以完全匹配   没有那些非常嵌套的相同   量词:假设每个“x”   代表更复杂的东西,   与某些字符串匹配   两个都是“x”。请参阅HTML部分   下面的文件是一个真实的例子。

     

让我们看看申请时会发生什么   这个正则表达式为xxxxxxxxxxy。首先   x +将匹配所有10个x字符。该   第二个x +失败。第一个x +然后   回溯到9场比赛,以及   第二个拿起剩下的x。   该组现已匹配一次。该   组重复,但在第一次失败   X +。因为一次重复   足够,小组匹配。 ÿ   匹配y,整体匹配   找到。声明正则表达式   功能齐全,代码运到了   客户,他的电脑爆炸了。   几乎。

     

当y时,上面的正则表达式变得难看   主题字符串中缺少。   当y失败时,正则表达式引擎   回溯。该小组有一个   迭代它可以回溯到。该   第二个x +只匹配一个x,所以它   不能回溯。但第一个x +可以   放弃一个x。第二个x +及时   匹配xx。该小组再次有一个   迭代,下一个失败,并且   你失败了。再次回溯,   第二个x +现在有一个回溯   位置,减少自己以匹配x。   该组尝试第二次迭代。   第一个x +匹配但第二个匹配   卡在琴弦的尽头。   再次回溯,第一个x + in   该组的第一次迭代减少了   本身为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)然后我想你开始   得到漂移。

     

如果您在10x字符串上尝试此正则表达式   在RegexBuddy的调试器中,它需要   2558步骤找出最终的y   不见了。对于11x字符串,它   需要5118步。对于12,它需要   10238步。显然我们有一个   这里的指数复杂度为O(2 ^ n)。   在21倍时,调试器以2.8的速度下降   百万步,诊断坏情况   灾难性的回溯。

     

RegexBuddy对此感到宽容   检测到它正在进行圈子,和   中止匹配尝试。 其他正则表达式   引擎(如.NET)将继续发展   永远,而其他人会崩溃   堆栈溢出(如Perl,之前   版本5.10)。堆栈溢出是   特别是在Windows上讨厌,因为   他们倾向于提出你的申请   消失得无影无踪。   如果你运行网络,要非常小心   允许用户提供的服务   他们自己的正则表达式人   具有很少的正则表达式经验   提出惊人的技巧   指数复杂的常规   表达式。

我假设您将不得不在代码中处理它。我建议你联系Regexbuddy的作者,并询问检测这种情况需要什么。

答案 1 :(得分:1)

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

答案 2 :(得分:-1)

通常,正则表达式可能需要比预期更长的时间。您应该尝试使用像Regulator这样的工具的正则表达式。

答案 3 :(得分:-1)

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

如果您说想要匹配的内容,我可以尝试找出更有效的正则表达式。

答案 4 :(得分:-1)

在我看来,正如这种情况一样,正则表达式匹配呈指数级增长。请参阅BCL blog

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

请点击此处strip out strings with timeout