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

2022-08-31 08:47:57

方法的重要性是什么?
为什么我需要在获取对象之前编译正则表达式字符串?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

该方法总是在某个时候被调用;这是创建 Pattern 对象的唯一方法。所以问题真的是,你为什么要明确地称呼它?一个原因是您需要对 Matcher 对象的引用,以便可以使用其方法,例如检索捕获组的内容。获得 Matcher 对象的唯一方法是通过 Pattern 对象的方法,而获得 Pattern 对象的唯一方法是通过该方法。然后是与 不同于 String 或 Pattern 类的方法。compile()group(int)matcher()compile()find()matches()

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

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 的方法是否与 有关。NET 的修饰符;答案是否定的。Java 的方法仅等效于 。NET 的正则表达式构造函数。指定选项时:compile()RegexOptions.CompiledPattern.compile()Compiled

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

...它将正则表达式直接编译为CIL字节代码,使其执行得更快,但在前期处理和内存使用方面付出了巨大的代价 - 将其视为正则表达式的类固醇。Java没有等价物;在幕后创建的模式与您使用 显式创建的模式之间没有区别。String#matches(String)Pattern#compile(String)

(编辑:我最初说所有.NET正则表达式对象都被缓存,这是不正确的。从 .NET 2.0 开始,自动缓存仅使用静态方法(如 )发生,而不是直接调用正则表达式构造函数时。裁判Regex.Matches())


答案 2

编译分析正则表达式并生成内存中的表示形式。与匹配项相比,编译的开销很大。如果重复使用某个模式它将获得一些性能来缓存已编译的模式。