正则表达式导致C#中CPU使用率异常高

时间:2013-06-30 03:15:04

标签: c# .net regex

在最近阅读了一个被称为“灾难性回溯”的现象之后,似乎我自己的正则表达式模式正在引发某种CPU问题。我使用这个表达式来扫描100k-200k字符的大型HTML字符串。该模式匹配IP:端口格式的IP地址(例如1.1.1.1:90)。模式如下:

private static Regex regIp = new Regex(@"(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9])\." +
        @"(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4]" +
        @"[0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}" +
        @"[0-9]{2}|[1-9]{1}[0-9]{1}|[0-9])\:[0-9]{1,5}", 
        RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.CultureInvariant);

表达式使用如下:

MatchCollection matchCol = regIp.Matches(response);

foreach (Match m in matchCol)
{ 
    doWorkWithMatch(m);
}

通过此正则表达式模式运行大约100个字符串后,它开始阻塞计算机并使用99%的CPU。是否有更合理的方法来构造此表达式以减少CPU使用并避免回溯?我不确定回溯是否正在发生,或者它只是同时执行正则表达式评估的太多线程的问题 - 欢迎所有输入。

4 个答案:

答案 0 :(得分:5)

为什么要使用正则表达式进行语法分析和验证

你应该使用这个正则表达式来解析字符串

\d+[.]\d+[.]\d+[.]\d+(:\d+)?

然后您可以通过将它们解析为int然后检查范围来检查该IP地址是否具有有效范围

答案 1 :(得分:2)

这个正则表达式看起来设计得很好,如果你的准确率达到100%,我就无法看到你能改进它的任何地方。但是,您可以测试是否可能始终有效的简化方法可以改善结果。

\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:\d{1,5}

显然,这可能会遇到像999.999.999.999:999那样不正确的事情。但是你必须问自己是否会出现这种不切实际的输入。如果这确实提高了性能,并且您有理由相信您不会像我的示例那样疯狂输入,那么请使用它并使用更准确的正则表达式来剔除列表。

答案 2 :(得分:2)

这是我用于测试和验证IP地址的正则表达式

我在最后添加了端口测试:

(?:(?:1[0-9]{2}|2[0-4][0-9]|25[0-5]|[1-9][0-9]|[0-9])\.){3}(?:1[0-9]{2}|2[0-4][0-9]|25[0-5]|[1-9][0-9]|[0-9]):[0-9]{1,5}

enter image description here

我看到你也捕获了所有单独的八位字节,你可以通过使用非捕获(?: ... )语法来提升性能,然后只需将已验证的字符串拆分为非数字。

答案 3 :(得分:0)

也许你可以对结果进行分组并在以后测试它们,不要超过255和65535这个端口,就像在Daniel Gimenez的答案中一样,但是对于组(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\:(\d{1,5}),然后对匹配的组进行测试。< / p>

在正则表达式中包含这么多|通常是个坏主意。