String replaceAll()与Matcher replaceAll()(性能差异)

时间:2009-09-23 16:00:30

标签: java regex string replaceall

非常简单的问题,但这是来自C / C ++人员进入Java的复杂性。

我知道我可以启动jUnit和我自己的一些性能测试来得到答案;但我只是想知道这是否在那里。

在性能方面,String.replaceAll()和Matcher.replaceAll()(从Regex.Pattern创建的Matcher对象)之间是否存在已知差异?

此外,两者之间的高级API是什么区别? (不变性,处理空白,处理空字符串,制作咖啡等)。

7 个答案:

答案 0 :(得分:73)

根据String.replaceAll的文档,它有关于调用方法的以下内容:

  

调用此方法   表格str.replaceAll(regex, repl)   产生与结果完全相同的结果   表达

Pattern.compile(regex).matcher(str).replaceAll(repl)

因此,可以预期调用String.replaceAll和明确创建MatcherPattern之间的性能应该相同。

修改

正如评论中指出的那样,对replaceAllString的{​​{1}}的单次调用,性能差异不存在,但是,如果需要的话要对Matcher执行多次调用,人们会认为保持编译的replaceAll是有益的,因此不必每次都执行相对昂贵的正则表达式模式编译。

答案 1 :(得分:23)

String.replaceAll()的源代码:

public String replaceAll(String regex, String replacement) {
    return Pattern.compile(regex).matcher(this).replaceAll(replacement);
}

首先要编译模式 - 如果要在短字符串上使用相同的模式多次运行它,如果重用一个已编译的模式,性能会好得多。

答案 2 :(得分:9)

主要区别在于,如果你抓住用于生成Pattern的{​​{1}},就可以避免每次使用它时重新编译正则表达式。通过Matcher,您无法像这样“缓存”。

如果每次使用不同的正则表达式,使用String类的String都可以。如果要将相同的正则表达式应用于多个字符串,请创建一个replaceAll并重复使用它。

答案 3 :(得分:6)

不变性/线程安全性:编译模式是不可变的,匹配器不是。 (见Is Java Regex Thread Safe?

处理空字符串:replaceAll应该优雅地处理空字符串(它与空输入字符串模式不匹配)

制作咖啡等:最后我听说,String和Pattern以及Matcher都没有任何API功能。

编辑:至于处理NULL,String和Pattern的文档没有明确说明,但我怀疑他们会抛出一个NullPointerException,因为他们期望一个String。

答案 4 :(得分:4)

String.replaceAll的实施告诉您需要知道的一切:

return Pattern.compile(regex).matcher(this).replaceAll(replacement);

(文档说同样的话。)

虽然我没有检查过缓存,但我当然希望编译模式一次并保持静态引用比使用相同的方法调用Pattern.compile更有效每次模式。如果有一个缓存,它将是一个小的效率节省 - 如果没有它可能是一个大的。

答案 5 :(得分:4)

不同之处在于String.replaceAll()每次调用时都会编译正则表达式。 .NET的静态Regex.Replace()方法没有等价物,它自动缓存已编译的正则表达式。通常,replaceAll()只能执行一次,但如果您要使用相同的正则表达式重复调用它,尤其是在循环中,则应创建一个Pattern对象并使用Matcher方法。

您也可以提前创建Matcher,并使用其reset()方法为每次使用重新定位:

Matcher m = Pattern.compile(regex).matcher("");
for (String s : targets)
{
  System.out.println(m.reset(s).replaceAll(repl));
}

当然,重用Matcher的性能优势远不如重用模式那么好。

答案 6 :(得分:0)

其他答案足以涵盖OP的性能部分,但Matcher::replaceAllString::replaceAll之间的另一个差异也是编译自己的Pattern的原因。当您自己编译Pattern时,有一些选项,如标志,用于修改正则表达式的应用方式。例如:

Pattern myPattern = Pattern.compile(myRegex, Pattern.CASE_INSENSITIVE);

Matcher将应用您拨打Matcher::replaceAll时设置的所有标记。

您还可以设置其他标志。大多数情况下,我只想指出PatternMatcher API有很多选项,这是超越简单String::replaceAll

的主要原因