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