ReplaceAll with java8 lambda functions

2022-09-05 00:34:38

给定以下变量

templateText = "Hi ${name}";
variables.put("name", "Joe");

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

 variables.keySet().forEach(k -> templateText.replaceAll("\\${\\{"+ k +"\\}"  variables.get(k)));

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

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

当然,我在这里错过了一些东西:)


答案 1

爪哇 8

在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);

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

在 Java 8 中功能更强大

如果你想要一个更像 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;
}

并将其用作

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

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

与上面关于和相同的注释适用 - 如果您不希望您的函数处理它,则可能需要强制执行方法内部。$\quoteReplacement()replaceAll()replacer

Java 9 及更高版本

Java 9引入了Matcher.replaceAll(Function),它基本上实现了与上面的功能版本相同的功能。有关更多详细信息,请参阅Jesse Glick的答案


答案 2

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

身份

identity是约化函数的初始值,即 。accumulator

蓄电池

accumulator约化为 ,如果流是按顺序进行的,则表示下一个约简。identityresultidentity

合路器

此函数永远不会按顺序流调用。它计算下一个来自和并行流。identityidentityresult

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);

推荐