问题
Pattern.compile()
方法的重要性是什么?
为什么我需要在获取Matcher
对象之前编译正则表达式字符串?
例如 :
String regex = "((\\S+)\\s*some\\s*";
Pattern pattern = Pattern.compile(regex); // why do I need to compile
Matcher matcher = pattern.matcher(text);
#1 热门回答(123 赞)
总是在某个时刻调用compile()
方法;这是创建Pattern对象的唯一方法。所以问题是,你为什么要明确地称之为****?一个原因是你需要对Matcher对象的引用,以便你可以使用其方法,如group(int)
来检索捕获组的内容。获取Matcher对象的唯一方法是通过Pattern对象的matcher()
方法,获得Pattern对象的唯一方法是通过compile()
方法。然后是find()
方法,与matches()
不同,它不会在String或Pattern类中重复。
另一个原因是避免反复创建相同的Pattern对象。每次使用String中的一个正则表达式方法(或Pattern中的staticmatches()
方法)时,它都会创建一个新的Pattern和一个新的Matcher。所以这段代码片段:
for (String s : myStringList) {
if ( s.matches("\\d+") ) {
doSomething();
}
}
......完全等同于:
for (String s : myStringList) {
if ( Pattern.compile("\\d+").matcher(s).matches() ) {
doSomething();
}
}
显然,那是在做很多不必要的工作。事实上,编译正则表达式并实例化Pattern对象比执行实际匹配要花费更长的时间。因此,将该步骤拉出循环通常是有意义的。你也可以提前创建Matcher,尽管它们并不是那么昂贵:
Pattern p = Pattern.compile("\\d+");
Matcher m = p.matcher("");
for (String s : myStringList) {
if ( m.reset(s).matches() ) {
doSomething();
}
}
如果你熟悉.NET正则表达式,你可能想知道Java的compile()
方法是否与.NET的RegexOptions.Compiled
修饰符有关;答案是不。 Java的Pattern.compile()
方法仅仅等同于.NET的Regex构造函数。指定Compiled
选项时:
Regex r = new Regex(@"\d+", RegexOptions.Compiled);
...它将正则表达式直接编译为CIL字节代码,使其执行速度更快,但在前期处理和内存使用方面成本很高 - 将其视为正则表达式的类固醇。 Java没有等价物;在String#matches(String)
之后创建的模式与使用Pattern#compile(String)
明确创建的模式之间没有区别。
(编辑:我最初说所有的.NET Regex对象都是缓存的,这是不正确的。从.NET 2.0开始,只有静态方法如Regex.Matches()
才会发生自动缓存,而不是直接调用Regex构造函数时.ref)
#2 热门回答(33 赞)
Compile解析正则表达式并构建一个内存中表示.与匹配相比,编译的开销很大。如果你反复使用pattern**,**it将获得一些缓存编译模式的性能。
#3 热门回答(14 赞)
当你编译Pattern
Java时,会进行一些计算,以便在String
s中更快地找到匹配项。 (构建正则表达式的内存表示)
如果你要重复使用Pattern
次,你会发现每次创建新的Pattern
都会带来巨大的性能提升。
在仅使用Pattern一次的情况下,编译步骤似乎只是一行额外的代码,但事实上,它在一般情况下非常有用。