正则表达式匹配需要很长时间才能执行。

6

我编写了一个正则表达式,将文件路径解析为不同的组(驱动器、目录、文件名和扩展名)。

^((?<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";

=> OK

但是当我尝试用一个不匹配的路径进行测试时,就像这样:

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%的处理器。这是什么意思?


你有没有考虑在验证之前解析路径?参考链接:https://dev59.com/U0_Ta4cB1Zd3GeqPBHyj - kennytm
3
为什么你不使用Path类中的有用方法呢?提取这些信息无需使用正则表达式。 - Jens
1
RegEx 真的不是这里走的正确方式。我仍然想知道为什么这个 RegEx 会导致 regexr.com 崩溃 :> - atamanroman
4个回答

10
你遇到的问题被称为“灾难性回溯”,是由于你的正则表达式可以匹配字符串的开头的方式过多,这会导致在.NET中使用回溯正则表达式引擎时出现缓慢的性能。此处有更详细的信息。
我认为你在正则表达式中过度使用了**不意味着“连接”-它表示“零次或多次”。例如,在这里不应该有一个*
((?<DRIVE>[a-zA-Z]):\\)*

最多只能有一个驱动器规范。在这里应该使用?,否则如果您希望强制使用驱动器规范,则根本不需要量词。类似地,您的正则表达式中还有其他位置的量词是不正确的。


也许你可以在回答中加入这个链接,它很好地解释了这种情况的发生: http://www.regular-expressions.info/catastrophic.html 非常感谢你的好回答!(+1) - atamanroman

7

马克·拜尔斯是正确的,问题的原因是灾难性回溯,然而引起问题的是最后一部分,而不是匹配驱动器号码的部分。

例如,在

(?<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%。

要解决这个问题,通常需要避免重复元素的重复出现,避免交替匹配相同的内容,可能需要将匹配的某些部分放在原子组中,如果稍后的正则表达式无法匹配,则不会回溯到这些组中。

然而,在您的情况下,最好使用 .NET 的路径操作函数,这才是工作的正确工具。


非常感谢您清晰明了的回复。您是正确的,我将使用.NET框架上可用的函数! - RedPaladin


0

我会使用FileInfoPath类来获取信息。

如果您选择使用正则表达式,请注意正则表达式并不能匹配所有合法的文件名:您的正则表达式中缺少了许多合法的文件名标记。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接