Red*_*din 5 c# regex performance
我编写了一个正则表达式,将文件路径解析为不同的组(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})$))
Run Code Online (Sandbox Code Playgroud)
我在C#中做了一个测试.当我想测试的路径是正确的.结果非常快,这是我想要的.
string path = @"C:\Documents and Settings\jhr\My Documents\Visual Studio 2010\Projects\FileEncryptor\Dds.FileEncryptor\Dds.FileEncryptor.csproj";
Run Code Online (Sandbox Code Playgroud)
=>好的
但是,当我尝试使用我知道不匹配的路径进行测试时,如下所示:
string path = @"C:\Documents and Settings\jhr\My Documents\Visual Studio 2010\Projects\FileEncryptor\Dds.FileEncryptor\Dds.FileEncryptor?!??????";
Run Code Online (Sandbox Code Playgroud)
=> BUG
当我调用这部分代码时,测试会冻结
Match match = s_fileRegex.Match(path);
Run Code Online (Sandbox Code Playgroud)
当我查看我的Process Explorer时,我看到QTAgent32.exe进程挂在处理器的100%处.这是什么意思 ?
Mar*_*ers 10
您遇到的问题称为灾难性回溯,并且由于正则表达式可以匹配字符串开头的大量方法,由于.NET中的回溯正则表达式引擎而导致性能降低.
我认为你*在正则表达式中使用得太频繁了.*并不意味着"连接" - 它意味着"0次或更多次".例如,这里不应该有*:
((?<DRIVE>[a-zA-Z]):\\)*
Run Code Online (Sandbox Code Playgroud)
最多应该有一个驱动器规格.你应该?在这里使用,或者如果你想要驱动器规范是强制性的话,根本就没有量词.类似地,正则表达式中似乎存在量词不正确的其他位置.
Mark Byers是正确的,因为问题的原因是灾难性的回溯,然而这是导致问题的最后一部分,而不是与驱动器号匹配的位.
例如,在
(?<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})
$)
)
Run Code Online (Sandbox Code Playgroud)
你可以看到
([a-zA-Z0-9_\s_\-\.]*[a-zA-Z0-9_]+)
|
([a-zA-Z0-9_]+)
Run Code Online (Sandbox Code Playgroud)
可以通过多种不同的方式匹配相同的字符串,这些方式将随文件名的长度呈指数增长.
当正则表达式的扩展部分无法匹配时,正则表达式引擎回溯并为文件名部分尝试不同的排列,希望这使得扩展部分能够匹配 - 当然它永远不会,但正则表达式引擎可以不清楚这一点.RegexBuddy,当被要求在您提供的路径上测试正则表达式时,在1.000.000次迭代后中止匹配尝试.C#正则表达式引擎将继续运行,直到它耗尽所有排列,在此期间将CPU固定在100%.
为了解决这个问题,通常需要避免重复元素的重复,以避免与相同事物匹配的交替,并且可能将匹配的部分包含在原子组中,如果正则表达式的后续部分失败则不会回溯到原子组中.
但是,在您的情况下,最好使用正确的工具来完成工作,这些是.NET的路径操作功能.
为什么不直接使用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减去驱动程序的内容
文件名:http://msdn.microsoft.com/en-us/library/system.io.path.getfilenamewithoutextension.aspx
扩展:http://msdn.microsoft.com/en-us/library/system.io.path.getextension.aspx