所以我在java中学习正则表达式并且想知道为什么当我执行这段代码时
String xxx = "(\\s+)?(c:/|c:\\\\|C:\\\\|C:/|c:\\|C:\\))?(\\w+(/|\\\\)?)+(/|\\\\)\\w+.[a-z]+";
String x = "C:\\Users\\esteban\\Desktop\\Java_file_testing\\file3.txt";
if(x.matches(xxx)) {
System.out.println("matches");
}else {
System.out.println("no match found ");
}
这会打印matches
,但是当我删除.txt
时,处理没有任何响应,我做错了吗?
答案 0 :(得分:3)
你偶然发现了一个catastrophic backtracking的案例!
当你写(\\w+(/|\\\\)?)+
时,你基本上是将(\\w+)+
模式引入你的正则表达式。这使得正则表达式引擎有机会以多种方式匹配相同的字符串(使用内部或外部+
) - 可能路径的数量呈指数增长,并且由于引擎必须尝试所有可能的方式在声明失败之前进行匹配需要永远返回一个值。
另外,关于你的正则表达式的一些一般性评论:
c:\\|
将匹配字符串c:|
/|\\\\
只是[/\\\\]
(\s+)?
是\s*
.
是一个需要转义的通配符(“除了换行符之外的任何东西”)c
/ C
版本,使用[cC]
或制作整个正则表达式case insensitive (?:...)
可以减轻某些工作的引擎考虑到这些,首次尝试精神的正则表达式可能是:
\\s*(?:[cC]:[/\\\\])?(?:\\w+[/\\\\])*\\w+\\.[a-z]+
在(?:\\w+[/\\\\])
中,字符类[/\\\\]
不再是可选项,从而避免使用(\\w+)+
模式:请参阅demo here。
有关灾难性回溯的更多信息,我建议弗里德尔就the perl journal上的主题撰写优秀(和有趣!)的文章。
答案 1 :(得分:1)
你的正则表达式使用匹配.
[A-Za-z0-9_]
字符
你必须逃避点:
(\\s+)?(c:/|c:\\\\|C:\\\\|C:/|c:\\|C:\\))?(\\w+(/|\\\\)?)+(/|\\\\)\\w+\\.[a-z]+
here --------^
顺便说一下,你可以这样缩短你的正则表达式:
\s*[Cc]:(?:(?:\/|\\{1,2})\w+)+\.\w+
<强> Working demo 强>
请记住逃避反斜杠:
\\s*[Cc]:(?:(?:\\/|\\\\{1,2})\\w+)+\\.\\w+