为啥用 Regex.IsMatch 检查这个字符串会导致 CPU 达到 100%?
Posted
技术标签:
【中文标题】为啥用 Regex.IsMatch 检查这个字符串会导致 CPU 达到 100%?【英文标题】:Why does checking this string with Regex.IsMatch cause CPU to reach 100%?为什么用 Regex.IsMatch 检查这个字符串会导致 CPU 达到 100%? 【发布时间】:2015-09-22 12:48:31 【问题描述】:在特定字符串上使用Regex.IsMatch
(C#, .Net 4.5) 时,CPU 达到 100%。
字符串:
https://www.facebook.com/CashKingPirates/photos/a.197028616990372.62904.196982426994991/1186500984709792/?type=1&permPage=1
图案:
^http(s)?://([\w-]+.)+[\w-]+(/[\w- ./?%&=])?$
完整代码:
Regex.IsMatch("https://www.facebook.com/CashKingPirates/photos/a.197028616990372.62904.196982426994991/1186500984709792/?type=1&permPage=1",
@"^http(s)?://([\w-]+.)+[\w-]+(/[\w- ./?%&=])?$");
我发现编辑 URL 可以防止这个问题。编辑网址:
https://www.facebook.com/CashKingPirates/photos/a.197028616990372.62904.196982426994991/1186500984709792
但仍然非常有兴趣了解造成这种情况的原因。
【问题讨论】:
正则匹配涉及大量回溯。更多信息请阅读runaway regular expressions 由于您没有在点前加反斜杠,因此您的正则表达式可能是^http(s)?://.+$
的一个非常复杂的版本(即匹配 http:// 或 https:// 后跟任何内容)。
为什么不用URI类?
@SalmanA 在看到潜在危害后,我实际上从正则表达式更改为 URI.TryCreate。
【参考方案1】:
正如 nu11p01n73R 指出的那样,您的正则表达式有很多回溯。那是因为你的表达式的某些部分都可以匹配同一个东西,这给引擎提供了很多选择,它必须在找到结果之前尝试。
您可以通过更改正则表达式以使各个部分更加具体来避免这种情况。在您的情况下,原因是您想匹配一个真实的点,但使用了匹配所有字符 .
。你应该把它转义到\.
。
这应该已经大大减少了回溯需求并使其快速:
^http(s)?://([\w-]+\.)+[\w-]+(/[\w- ./?%&=])?$
而如果要实际匹配原始字符串,则需要在字符类末尾添加一个量词:
^http(s)?://([\w-]+\.)+[\w-]+(/[\w- ./?%&=]+)?$
↑
【讨论】:
谢谢,但您建议的正则表达式与原始字符串不匹配。不过速度很快。 确实,这是导致灾难性回溯的唯一且确切的原因:点未转义,不被视为文字字符并且可以匹配任何内容。 @Nir:请注意,这完全回答了您的问题。您现在可以轻松地纠正您的模式。【参考方案2】:我建议你检查http://regexr.com/网站,测试你的正则表达式。
正则表达式的更正版本如下:
^(https?://(?:[\w]+\.?[\w]+)+[\w]/?)([\w\./]+)(\?[\w-=&%]+)?$
它也有3组:
-
group1=主要网址(例如:facebook.com)
group2=子网址(例如:/CashKingPirates/photos/a.197028616990372.62904.196982426994991/1186500984709792/
group3=变量(例如:?type=1&permPage=1)
还要记住,要检查正则表达式中点 (.) 的实际字符,您必须使用 \。不是。
【讨论】:
我不能告诉你他问题的确切原因,但据我所知 [\w-]+ 在他的正则表达式中是完全没有必要的。 regxer 专为不支持lookbehinds的js设计。【参考方案3】:您的正则表达式因catastrophic backtracking
而受到影响。您可以简单地使用
^http(s)?://([\w.-])+(/[\w ./?%&=-]+)*$
查看演示。
https://regex101.com/r/cK4iV0/15
【讨论】:
这是一个糟糕的解决方案,会降低原始正则表达式的意图。以上是关于为啥用 Regex.IsMatch 检查这个字符串会导致 CPU 达到 100%?的主要内容,如果未能解决你的问题,请参考以下文章
有没有办法只使用 Regex.IsMatch 来匹配也有数字的字符串?
在 TextBox.Text 中退格后 Regex.IsMatch 不起作用
c#大于等于3小于等于99正则表达式怎么写? (Regex.IsMatch(textBox1.Text, "[3-9]1,"))