java.util.regex – Pattern.compile()的重要性?

Pattern.compile()方法的重要性是什么?
为什么在获取Matcher对象之前需要编译正则expression式string?

例如 :

 String regex = "((\\S+)\\s*some\\s*"; Pattern pattern = Pattern.compile(regex); // why do I need to compile Matcher matcher = pattern.matcher(text); 

compile()方法总是在某个时候调用; 这是创build一个Pattern对象的唯一方法。 所以问题是,你为什么要明确地调用它? 一个原因是你需要一个Matcher对象的引用,所以你可以使用它的方法,比如group(int)来获取捕获组的内容。 获取匹配对象的唯一方法是通过Pattern对象的matcher()方法,并且通过compile()方法来获取对象的唯一方法。 然后是find()方法,它不像matches()那样在String或Pattern类中不重复。

另一个原因是避免一遍又一遍地创build相同的Pattern对象。 每次在String中使用正则expression式驱动的方法(或Pattern中的静态matches()方法)时,都会创build一个新的Pattern和一个新的Matcher。 所以这个代码片段:

 for (String s : myStringList) { if ( s.matches("\\d+") ) { doSomething(); } } 

…完全等同于:

 for (String s : myStringList) { if ( Pattern.compile("\\d+").matcher(s).matches() ) { doSomething(); } } 

显然,这是做了很多不必要的工作。 实际上,编译正则expression式并实例化Pattern对象比执行实际匹配要花费更长的时间。 所以把这一步从循环中拉出来通常是有意义的。 您也可以提前创build匹配器,尽pipe它们并不昂贵:

 Pattern p = Pattern.compile("\\d+"); Matcher m = p.matcher(""); for (String s : myStringList) { if ( m.reset(s).matches() ) { doSomething(); } } 

如果您熟悉.NET正则expression式,您可能想知道Java的compile()方法是否与.NET的RegexOptions.Compiled修饰符有关。 答案是不。 Java的Pattern.compile()方法仅仅是.NET的Regex构造函数。 当您指定Compiled选项时:

 Regex r = new Regex(@"\d+", RegexOptions.Compiled); 

…它直接编译CIL字节代码的正则expression式,使其执行速度更快,但是在前期处理和内存使用方面花费巨大 – 将其视为正则expression式的类固化。 Java没有相应的东西; 在String#matches(String)后面创build的模式和使用Pattern#compile(String)显式创build的模式之间没有区别。

(编辑:我原来说,所有的.NET正则expression式对象caching,这是不正确的。自从.NET 2.0,自动caching只发生在像Regex.Matches()静态方法,而不是直接调用Regex构造函数。

编译parsing正则expression式并构build一个内存表示 。 与比赛相比,编译的开销很大。 如果你重复使用一个模式它会获得一些性能来caching编译模式。

在编译Pattern Java会进行一些计算,以便更快地查找String的匹配项。 (构build正则expression式的内存中表示)

如果您要重复使用该Pattern多次,您会看到每次创build一个新的Pattern性能大大提高。

在只使用Pattern一次的情况下,编译步骤看起来像是一个额外的代码行,但事实上,在一般情况下它可能非常有帮助。

这是性能和内存使用的问题,如果你需要使用它,编译和保持编译的模式。 一个典型的正则expression式的用法是validation用户input(格式) ,并为用户格式化输出数据 ,在这些类中保存编译后的模式,似乎很合理,因为他们通常称为很多。

下面是一个示例validation器,这真的叫很多:)

 public class AmountValidator { //Accept 123 - 123,456 - 123,345.34 private static final String AMOUNT_REGEX="\\d{1,3}(,\\d{3})*(\\.\\d{1,4})?|\\.\\d{1,4}"; //Compile and save the pattern private static final Pattern AMOUNT_PATTERN = Pattern.compile(AMOUNT_REGEX); public boolean validate(String amount){ if (!AMOUNT_PATTERN.matcher(amount).matches()) { return false; } return true; } } 

正如@Alan Moore所提到的,如果你的代码中有可重复使用的正则expression式(例如循环之前),你必须编译并保存模式以便重用。

预编译正则expression式会提高速度。 重新使用匹配器会给你另一个轻微的加速。 如果这个方法被频繁地调用,那么在一个循环内调用,整体性能肯定会上升。