我正在使用以下正则表达式来检查有效的文件路径:
^(?:[a-zA-Z]\:\\|\\\\)([^\\\/\:\*\?\<\>\"\|]+(\\){0,1})+$
使用测试字符串V:\Sample Names\Libraries\DeveloperLib\DeveloperComDlgs\res
被视为有效。我甚至可以在字符串的开头添加无效字符而不会出现问题。但是,当我在字符串的末尾添加无效字符时,网页会从灾难性的回溯中冻结。
在这个正则表达式字符串中导致这种情况的原因是什么?
完整字符串: ^(?:[a-zA-Z]\:\\|\\\\)([^\\\/\:\*\?\<\>\"\|]+(\\){0,1})+$
第一组: (?:[a-zA-Z]\:\\|\\\\)
第二组: ([^\\\/\:\*\?\<\>\"\|]+(\\){0,1})
[^\\\/\:\*\?\<\>\"\|]+
(\\){0,1}
我认为可能导致问题的{0, 1}
因为这允许回溯但我不确定。有什么想法吗?
答案 0 :(得分:2)
您当前的正则表达式可以写成^(?:[a-zA-Z]:\\|\\\\)([^\\\/\:*?<>"|]+\\?)+$
:在?
{0,1}
之后注意\\
量词(它等于+
限制量词)量化组。
一旦这样的模式如(a+b?)+
存在于模式中,就很有可能发生灾难性的回溯。比赛时,一切都很好,比如c:\12\34\aaaaaaaaaaaaaaaaaaa
is matched fine,但是一旦不允许的字符显示导致不匹配,(尝试在最后添加*
,c:\12\34\aaaaaaaaaaaaaaaaaaa*
) ,issue will appear。
要解决此问题,可以匹配相同文本的量化子模式不能立即相继跟随。并且使用可选的组,其中每个子模式都是强制性的。
在大多数情况下,您需要使用展开的a+(ba+)*
替换这些模式部分(一次或多次出现a
后跟0个或多个b
序列(不再是可选的)本身)然后发生一次或多次a
(因此,在一个a
和下一个a
之间必须有一个b
。如果你需要匹配一个\
最后的可选^(a+b?)+$
(因为b
实际上可能与字符串末尾的b?
匹配),您需要在结尾处添加a+(ba+)*b?
:{{1} }。
所以,将其转换为您当前的场景:
^(?:[a-zA-Z]:\\|\\\\)[^\\\/\:*?<>"|]+(?:\\[^\\\/\:*?<>"|]+)*$
或者如果最后允许\
:
^(?:[a-zA-Z]:\\|\\\\)[^\\\/\:*?<>"|]+(?:\\[^\\\/\:*?<>"|]+)*\\?$
| a+ ( b a+ )* b?
查看不匹配时的fails gracefully或matches as expected。
正如@anubhava建议的那样,你可以通过使用所有权量词(或原子组代替,因为,例如.NET正则表达式引擎不支持所有权)来进一步增强性能禁止任何回溯进入分组模式。一旦匹配,这些模式就不会被重新尝试,因此,失败可能会更快:
^(?:[a-zA-Z]:\\|\\\\)[^\\\/\:*?<>"|]+(?:\\[^\\\/\:*?<>"|]+)*+\\?$
^
或原子组示例:
^(?:[a-zA-Z]:\\|\\\\)(?>[^\\\/\:*?<>"|]+(?:\\[^\\\/\:*?<>"|]+)*)\\?$
^^^ ^
请注意:
不是特殊的正则表达式元字符,不应对其进行转义。在角色类中,只有-
,^
,\
和]
通常需要转义,其他所有其他都不是特别的。
在The Explosive Quantifier Trap查看有关灾难性回溯的详情。