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

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

^((?[a-zA-Z]):\\)*((?[a-zA-Z0-9_]+(([a-zA-Z0-9_\s_\-\.]*[a-zA-Z0-9_]+)|([a-zA-Z0-9_]+)))\\)*(?([a-zA-Z0-9_]+(([a-zA-Z0-9_\s_\-\.]*[a-zA-Z0-9_]+)|([a-zA-Z0-9_]+))\.(?[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?!??????"; 

=> BUG

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

 Match match = s_fileRegex.Match(path); 

当我查看我的Process Explorer时,我看到QTAgent32.exe进程挂在处理器的100%处。 这是什么意思 ?

您遇到的问题称为灾难性回溯 ,这是由于正则表达式可以匹配字符串开头的大量方法,由于.NET中的回溯正则表达式引擎而导致性能降低。

我认为你在正则表达式中经常使用**并不意味着“连接” – 它意味着“0次或更多次”。 例如,这里不应该有*

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

最多应该有一个驱动器规格。 你应该用? 相反,如果你想要驱动器规范是强制性的,或者根本没有量词。 类似地,正则表达式中似乎存在量词不正确的其他位置。

Mark Byers是正确的,因为问题的原因是灾难性的回溯 ,然而这是导致问题的最后一部分,而不是与驱动器号匹配的位。

例如,在

 (? ([a-zA-Z0-9_]+ ( ([a-zA-Z0-9_\s_\-\.]*[a-zA-Z0-9_]+) | ([a-zA-Z0-9_]+) )\. (?[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%。

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

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

为什么不直接使用System.IO.Path函数?

  • 驱动器: http : //msdn.microsoft.com/en-us/library/system.io.path.getpathroot.aspx

  • 目录: http : //msdn.microsoft.com/en-us/library/system.io.path.getdirectoryname.aspx减去Drive的内容

  • 文件名: http : //msdn.microsoft.com/en-us/library/system.io.path.getfilenamewithoutextension.aspx

  • 扩展: http : //msdn.microsoft.com/en-us/library/system.io.path.getextension.aspx

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

如果您选择使用正则表达式,请注意正则表达式与所有合法文件名都不匹配:正则表达式中缺少一大堆合法的文件名令牌。