在最近阅读了一个被称为“灾难性回溯”的现象之后,似乎我自己的正则表达式模式正在引发某种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使用并避免回溯?我不确定回溯是否正在发生,或者它只是同时执行正则表达式评估的太多线程的问题 - 欢迎所有输入。
答案 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}
我看到你也捕获了所有单独的八位字节,你可以通过使用非捕获(?:
... )
语法来提升性能,然后只需将已验证的字符串拆分为非数字。
答案 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>
在正则表达式中包含这么多|
通常是个坏主意。