Dadas las siguientes variables
templateText = "Hi ${name}"; variables.put("name", "Joe");Me gustaría reemplazar el marcador de posición ${name} con el valor "Joe" usando el siguiente código (eso no funciona)
variables.keySet().forEach(k -> templateText.replaceAll("\\${\\{"+ k +"\\}" variables.get(k)));Sin embargo, si lo hago de la manera "antigua", todo funciona perfectamente:
for (Entry<String, String> entry : variables.entrySet()){ String regex = "\\$\\{" + entry.getKey() + "\\}"; templateText = templateText.replaceAll(regex, entry.getValue()); }Seguramente me estoy perdiendo algo aquí :)
La forma correcta de implementar esto no ha cambiado en Java 8, se basa en 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); Tenga en cuenta que, como lo menciona drrob en los comentarios, la cadena de reemplazo de appendReplacement() puede contener referencias de grupo usando el signo $ y escapando usando \ . Si no lo desea, o si su String de reemplazo puede contener potencialmente esos caracteres, debe escaparlos usando Matcher.quoteReplacement() .
Si desea una versión más estilo Java-8, puede extraer el código de la placa de caldera de búsqueda y reemplazo en un método generalizado que toma una Function de reemplazo:
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; }y usarlo como
Pattern variablePattern = Pattern.compile("\\$\\{(.+?)\\}"); StringBuffer result = replaceAll(templateText, variablePattern, m -> variables.get(m.group(1))); Tenga en cuenta que tener un Pattern como parámetro (en lugar de una String ) permite que se almacene como una constante en lugar de volver a compilarlo cada vez.
Se aplica la misma observación que la anterior con respecto a $ y \ : es posible que desee aplicar el quoteReplacement() dentro del método replaceAll() si no desea que su función de replacer lo maneje.
Java 9 introdujo Matcher.replaceAll(Function) que básicamente implementa lo mismo que la versión funcional anterior. Consulte la respuesta de Jesse Glick para obtener más detalles.
también puede usar Stream.reduce(identity,accumulator,combiner) .
identity es el valor inicial para la función reductora que es accumulator .
accumulator reduciendo la identity al result , que es la identity para la próxima reducción si la secuencia es secuencial .
esta función nunca se llamará en flujo secuencial . calcula la siguiente identity a partir de la identity y da como result una secuencia paralela .
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);import java.util.HashMap; import java.util.Map; public class Repl { public static void main(String[] args) { Map<String, String> variables = new HashMap<>(); String templateText = "Hi, ${name} ${secondname}! My name is ${name} too :)"; variables.put("name", "Joe"); variables.put("secondname", "White"); templateText = variables.keySet().stream().reduce(templateText, (acc, e) -> acc.replaceAll("\\$\\{" + e + "\\}", variables.get(e))); System.out.println(templateText); } }producción:
¡Hola, Joe White! Mi nombre es Joe también :)
Sin embargo , no es la mejor idea reinventar la rueda y la forma preferida de lograr lo que desea sería usar apache commons lang como se indica aquí .
Map<String, String> valuesMap = new HashMap<String, String>(); valuesMap.put("animal", "quick brown fox"); valuesMap.put("target", "lazy dog"); String templateString = "The ${animal} jumped over the ${target}."; StrSubstitutor sub = new StrSubstitutor(valuesMap); String resolvedString = sub.replace(templateString);