【问题标题】:Regex match take a very long time to execute正则表达式匹配需要很长时间才能执行
【发布时间】:2011-03-25 03:05:19
【问题描述】:

我编写了一个正则表达式,将文件路径解析为不同的组(DRIVE、DIR、FILE、EXTENSION)。

^((?<DRIVE>[a-zA-Z]):\\)*((?<DIR>[a-zA-Z0-9_]+(([a-zA-Z0-9_\s_\-\.]*[a-zA-Z0-9_]+)|([a-zA-Z0-9_]+)))\\)*(?<FILE>([a-zA-Z0-9_]+(([a-zA-Z0-9_\s_\-\.]*[a-zA-Z0-9_]+)|([a-zA-Z0-9_]+))\.(?<EXTENSION>[a-zA-Z0-9]{1,6})$))

我用 C# 做了一个测试。当我要测试的路径正确时。结果很快,这是我所期望的。

string path = @"C:\Documents and Settings\jhr\My Documents\Visual Studio 2010\Projects\FileEncryptor\Dds.FileEncryptor\Dds.FileEncryptor.csproj";

=> 好的

但是当我尝试使用我知道不匹配的路径进行测试时,如下所示:

string path = @"C:\Documents and Settings\jhr\My Documents\Visual Studio 2010\Projects\FileEncryptor\Dds.FileEncryptor\Dds.FileEncryptor?!??????";

=> 错误

当我调用这部分代码时测试冻结

Match match = s_fileRegex.Match(path);

当我查看我的进程资源管理器时,我看到进程 QTAgent32.exe 挂在我的处理器的 100% 处。什么意思?

【问题讨论】:

  • 您在验证之前是否考虑过parsing the path
  • 为什么不使用 Path 类中的有用方法?无需使用正则表达式来提取此信息。
  • RegEx 确实是错误的方式。我仍然想知道为什么这个 RegEx 会杀死 regexr.com :>

标签: c# regex performance


【解决方案1】:

Mark Byers 是正确的,因为问题的原因是 catastrophic backtracking,但它是导致问题的最后一部分,而不是与驱动器号匹配的位。

例如,在

(?<FILE>
  ([a-zA-Z0-9_]+
    (
      ([a-zA-Z0-9_\s_\-\.]*[a-zA-Z0-9_]+)
    |
      ([a-zA-Z0-9_]+)
    )\.
    (?<EXTENSION>[a-zA-Z0-9]{1,6})
  $)
)

你可以看到

([a-zA-Z0-9_\s_\-\.]*[a-zA-Z0-9_]+)
|
([a-zA-Z0-9_]+)

可以通过多种不同方式匹配同一个字符串,这些方式会随着文件名的长度呈指数增长。

当正则表达式的扩展部分无法匹配时,正则表达式引擎会回溯并尝试对文件名部分进行不同的排列,希望这可以使扩展部分匹配 - 当然它永远不会匹配,但是正则表达式引擎无法弄清楚。 RegexBuddy,当被要求在您提供的路径上测试正则表达式时,在 1.000.000 次迭代后中止匹配尝试。 C# 正则表达式引擎将一直运行,直到用尽所有排列,在此期间将您的 CPU 固定在 100%。

为了解决这个问题,通常需要避免重复元素的重复,避免匹配相同事物的交替,并可能将匹配的部分包含在 atomic groups 中,如果后面的部分不会回溯到正则表达式失败。

但是,在您的情况下,最好使用正确的工具来完成这项工作,这些是 .NET 的路径操作功能。

【讨论】:

  • 感谢您非常明确的答复。你说得对,我将使用 .NET 框架上的可用函数!
【解决方案2】:

您遇到的问题称为catastrophic backtracking,这是由于您的正则表达式可以通过多种方式匹配字符串的开头,由于 .NET 中的回溯正则表达式引擎导致性能下降。

我认为您在正则表达式中过于频繁地使用** 并不意味着“连接”——它意味着“0 次或多次”。例如这里不应该有*

((?<DRIVE>[a-zA-Z]):\\)*

最多应该有一个驱动器规格。您应该在此处使用?,否则如果您希望驱动器规范是强制性的,则根本没有量词。同样,您的正则表达式中似乎还有其他地方量词不正确。

【讨论】:

【解决方案3】:

我只是使用FileInfoPath 类来获取信息。

如果您选择使用正则表达式, 然后请注意,正则表达式并不匹配所有合法文件名:您的正则表达式中缺少一大堆合法文件名标记。

【讨论】:

    【解决方案4】:
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-03
    • 2011-03-14
    • 2021-01-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多