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

Suv*_*apa 44 java regex string replaceall

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

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

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

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

coo*_*ird 75

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

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

Pattern.compile(regex).matcher(str).replaceAll(repl)
Run Code Online (Sandbox Code Playgroud)

因此,可以预期调用之间的性能String.replaceAll,以及显式创建MatcherPattern应该是相同的.

编辑

正如在评论中指出的那样,对于replaceAll来自String或的单个调用,性能差异是不存在的Matcher,但是,如果需要执行多次调用replaceAll,人们会认为保持编译是有益的.Pattern因此,不必每次都执行相对昂贵的正则表达式模式编译.

  • 除了,如下所述,模式编译的性能损失.如果你使用常量正则表达式,编译它并将其粘贴在一个静态常量中. (11认同)
  • @aliteralmind持有Matcher的FWIW并非线程安全.我们在生产中发现了这种困难,并导致一些损坏的XML字符串.请参阅http://www.javamex.com/tutorials/regular_expressions/thread_safety.shtml (3认同)
  • 您最后的"因此"评论仅适用于1次通话,在这种情况下,性能指标确实无关紧要.如果使用相同的正则表达式重复调用replaceAll,则String.replaceAll比缓存已编译的模式慢. (2认同)
  • 实际上,重复使用后,抓住Matcher会更好.使用`Pattern.compile(...).matcher("忽略输入")`创建它,然后将它与`theMatcher.reset(theString).replaceAll(...)一起使用 (2认同)

Mic*_*rdt 23

源代码String.replaceAll():

public String replaceAll(String regex, String replacement) {
    return Pattern.compile(regex).matcher(this).replaceAll(replacement);
}
Run Code Online (Sandbox Code Playgroud)

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


eri*_*son 9

主要的区别在于,如果你持有Pattern用于生成的Matcher,你可以避免每次使用它时重新编译正则表达式.经历过String,你没有像这样"缓存"的能力.

如果你每次都有不同的正则表达式,那么使用这个StringreplaceAll很好.如果要将相同的正则表达式应用于多个字符串,请创建一个Pattern并重复使用它.


Jas*_*n S 6

不变性/线程安全:编译模式是不可变的,匹配器不是.(请参阅Java Regex线程安全吗?)

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

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

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


Jon*_*eet 5

的实现String.replaceAll告诉你你需要知道的一切:

return Pattern.compile(regex).matcher(this).replaceAll(replacement);
Run Code Online (Sandbox Code Playgroud)

(而且文档也说了同样的话。)

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


Ala*_*ore 5

不同之处在于 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));
}
Run Code Online (Sandbox Code Playgroud)

当然,重用 Matcher 的性能优势远不如重用 Pattern。