String.replaceAll比自己完成工作慢得多

时间:2011-06-07 08:15:53

标签: java regex string replace

我有一段旧代码,用于在字符串中执行查找和替换标记。

它会收到fromto对的地图,对它们进行迭代,对于每个对,迭代目标字符串,使用{{1}查找from },并将其替换为indexOf()的值。它完成to上的所有工作,最终返回StringBuffer

我用这一行替换了代码:String
我进行了一些比较性能测试 在比较replaceAll("[,. ]*", "");次迭代时,我得到了这个:

  

旧代码:1287ms
  新代码:4605ms

长3倍!

然后我尝试将其替换为1,000,000的3次调用:
 replace
 replace(",", "");
 replace(".", "");

这导致以下结果:

  

旧代码:1295
  新代码:3524

2倍!

知道为什么replace(" ", "");replace如此低效?我可以做些什么来加快速度吗?


编辑:感谢所有答案 - 主要问题确实replaceAll没有做我想做的事情。将其更改为[,. ]*几乎等于非基于正则表达式的解决方案的性能。 使用预编译的正则表达式有所帮助,但是很少。 (这是一个非常适用于我的问题的解决方案。

测试代码:
Replace string with Regex: [,. ]*
Replace string with Regex: [,. ]+
Replace string with Regex: [,. ]+ and Pre-Compiled Pattern

4 个答案:

答案 0 :(得分:54)

虽然使用正则表达式会对某些性能产生影响,但它不应该那么糟糕。

请注意,使用String.replaceAll()会编译正则表达式每次。\ n

您可以通过明确使用Pattern对象来避免这种情况:

Pattern p = Pattern.compile("[,. ]+");

// repeat only the following part:
String output = p.matcher(input).replaceAll("");

另请注意,使用+代替*可以避免替换空字符串,因此也可能会加快处理速度。

答案 1 :(得分:7)

replacereplaceAll在内部使用正则表达式,在大多数情况下,与performance impact相比,会产生严重的StringUtils.replace(..)

String.replaceAll()

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

String.replace()使用下面的Pattern.compile。

public String replace(CharSequence target, CharSequence replacement) {
  return Pattern.compile(target.toString(), Pattern.LITERAL)
         .matcher(this ).replaceAll(
           Matcher.quoteReplacement(replacement.toString()));
}

另见Replace all occurrences of substring in a string - which is more efficient in Java?

答案 2 :(得分:3)

正如我发表评论[,。 ] *匹配空字符串“”。因此,字符之间的每个“空格”都与模式匹配。它仅在性能中被注意到,因为你用“”替换了很多“”。

尝试这样做:

Pattern p = Pattern.compile("[,. ]*");
System.out.println(p.matcher("Hello World").replaceAll("$$$");

它返回:

ħ$$$Ë$$$升$$$ö$$$$$$W¯¯$$$ö$$$ř$$$升$$$ d $$$!$$$

难怪“手工”这样做比较慢!你应该试试[,。 ] +

答案 3 :(得分:1)

说到replaceAll("[,. ]*", ""),它并不是一个惊喜,因为它依赖于正则表达式。正则表达式引擎创建一个自动机,它在输入上运行。预计会有一些开销。

第二种方法(replace(",", "")...)也在内部使用正则表达式。然而,这里使用Pattern.LITERAL编译给定模式,因此正则表达式开销应该是可以忽略的。)在这种情况下,可能是由于Strings是不可变的这一事实(无论你做了多少改变,你都会创建一个新的字符串),因此不如StringBuffers那样有效地操作字符串。