ReplaceAll与java8 lambda函数

use*_*540 9 java lambda java-8

给出以下变量

templateText = "Hi ${name}";
variables.put("name", "Joe");
Run Code Online (Sandbox Code Playgroud)

我想使用以下代码(不起作用)将值占位符$ {name}替换为值"Joe"

 variables.keySet().forEach(k -> templateText.replaceAll("\\${\\{"+ k +"\\}"  variables.get(k)));
Run Code Online (Sandbox Code Playgroud)

但是,如果我采用"旧式"的方式,一切都很完美:

for (Entry<String, String> entry : variables.entrySet()){
    String  regex = "\\$\\{" + entry.getKey() + "\\}";          
    templateText =  templateText.replaceAll(regex, entry.getValue());           
   }
Run Code Online (Sandbox Code Playgroud)

当然我在这里遗漏了一些东西:)

Did*_*r L 16

实现这一点的正确方法在Java 8中没有改变,它基于appendReplacement()/ appendTail():

Pattern variablePattern = Pattern.compile("\\$\\{(.+?)\\}");
Matcher matcher = variablePattern.matcher(templateText);
StringBuffer result = new StringBuffer();
while (matcher.find()) {
    matcher.appendReplacement(result, variables.get(matcher.group(1)));
}
matcher.appendTail(result);
System.out.println(result);
Run Code Online (Sandbox Code Playgroud)

请注意,正如drrob在评论中所提到的,替换字符串appendReplacement()可以包含使用$符号的组引用,并使用转义\.如果不需要,或者替换String可能包含这些字符,则应使用它们进行转义Matcher.quoteReplacement().


如果你想要一个更加Java-8风格的版本,你可以将搜索和替换样板代码提取到一个需要替换的通用方法中Function:

private static StringBuffer replaceAll(String templateText, Pattern pattern,
                                       Function<Matcher, String> replacer) {
    Matcher matcher = pattern.matcher(templateText);
    StringBuffer result = new StringBuffer();
    while (matcher.find()) {
        matcher.appendReplacement(result, replacer.apply(matcher));
    }
    matcher.appendTail(result);
    return result;
}
Run Code Online (Sandbox Code Playgroud)

并用它作为

Pattern variablePattern = Pattern.compile("\\$\\{(.+?)\\}");
StringBuffer result = replaceAll(templateText, variablePattern,
                                 m -> variables.get(m.group(1)));
Run Code Online (Sandbox Code Playgroud)

请注意,使用Patternas参数(而不是a String)允许将其存储为常量,而不是每次都重新编译它.

同样的评论适用的有关上述$\-你可能要执行quoteReplacement()里面replaceAll()的方法,如果你不想让你的replacer函数来处理它.

  • 这实际上是更好的IMO然后*破*版本的上升答案.加一 (3认同)
  • 您几乎肯定希望在Matcher.quoteReplacement()中包装replacer返回值.替换字符串将斜杠和美元符号解释为引用其他组的方式.如果被替换的每个变量是独立的,并且应该按字面处理,那么这种行为是不合需要的.随之而来的是微妙的错误. (2认同)

hol*_*ava 9

你也可以使用Stream.reduce(identity,accumulator,combiner).

身分

identity是减少函数的初始值accumulator.

累加器

accumulator如果流是顺序的,则减少identityresult,即identity下一次减少.

组合

永远不会在顺序流中调用此函数.它计算下一个identityidentity&result并行流.

BinaryOperator<String> combinerNeverBeCalledInSequentiallyStream=(identity,t) -> {
   throw new IllegalStateException("Can't be used in parallel stream");
};

String result = variables.entrySet().stream()
            .reduce(templateText
                   , (it, var) -> it.replaceAll(format("\\$\\{%s\\}", var.getKey())
                                               , var.getValue())
                   , combinerNeverBeCalledInSequentiallyStream);
Run Code Online (Sandbox Code Playgroud)

  • @ holi-java你在这里破坏了关联性,这并不能正常工作; 即使你提供了`combiner`. (3认同)