代码之家  ›  专栏  ›  技术社区  ›  S.P

字符串replaceall()与matcher replaceall()(性能差异)

  •  42
  • S.P  · 技术社区  · 15 年前

    很简单的问题,但是这是来自C/C++的人进入Java复杂的地方。

    我知道我可以自己启动JUnit和一些性能测试来获得答案;但我只是想知道这是否存在。

    在性能方面,string.replaceall()和matcher.replaceall()(在从regex.pattern创建的matcher对象上)之间是否存在已知的差异?

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

    7 回复  |  直到 8 年前
        1
  •  71
  •   coobird    15 年前

    根据文件 String.replaceAll ,关于调用方法,可以说:

    此方法的调用 形式 str.replaceAll(regex, repl) 产生的结果与 表达

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

    因此,可以预期在调用 字符串.replaceall ,并显式创建 Matcher Pattern 应该是一样的。

    编辑

    正如在评论中所指出的,性能差异不存在对于 replaceAll String 匹配器 但是,如果需要对 替换 ,我们希望保留编译的 模式 因此,不必每次都执行相对昂贵的正则表达式模式编译。

        2
  •  22
  •   Michael Borgwardt    15 年前

    源代码 String.replaceAll() :

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

    它必须首先编译模式——如果您要在短字符串上用相同的模式多次运行它,那么如果您重用一个已编译的模式,性能会更好。

        3
  •  9
  •   erickson    15 年前

    主要的区别是如果你抓住 Pattern 用于生产 Matcher ,您可以避免每次使用regex时重新编译它。经历 String 你没有这种“缓存”的能力。

    如果每次都有不同的regex,请使用 班的 replaceAll 很好。如果要对多个字符串应用相同的regex,请创建一个 图案 再用它。

        4
  •  6
  •   Community CDub    8 年前

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

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

    制作咖啡等:我最后听说,无论是字符串、模式还是Matcher都没有任何API特性。

    编辑:关于处理空值,字符串和模式的文档没有明确地这么说,但是我怀疑他们会抛出nullpointerException,因为他们需要一个字符串。

        5
  •  4
  •   Jon Skeet    15 年前

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

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

    (医生也这么说。)

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

        6
  •  4
  •   Alan Moore Chris Ballance    15 年前

    不同的是,每次调用regex时,string.replaceall()都会编译它。没有与.NET的静态regex.replace()方法等效的方法,该方法自动缓存已编译的regex。通常,replaceall()只能执行一次,但如果要用同一个regex重复调用它,尤其是在循环中,则应创建一个模式对象并使用matcher方法。

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

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

    当然,重用Matcher的性能优势远不及重用模式。

        7
  •  0
  •   Indigenuity    8 年前

    其他答案充分涵盖了操作的性能部分,但是 Matcher::replaceAll String::replaceAll 也是编译自己的 Pattern . 当您编译 模式 您自己也可以使用诸如标志之类的选项来修改regex的应用方式。例如:

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

    这个 Matcher 将应用您在调用时设置的所有标志 匹配器::replaceall .

    您还可以设置其他标志。我只是想指出 模式 匹配器 API有很多选择,这是超越简单 字符串::replaceall