Gracias a todos por las respuestas!
La respuesta de Gizmo fue definitivamente fuera de la caja, y una gran solución, pero lamentablemente no es apropiada ya que el formato no puede limitarse a lo que hace la clase de formateador en este caso.
Adam Paynter realmente llegó al corazón de la cuestión, con el patrón correcto.
Peter Nix y Sean Bright tuvieron una gran solución para evitar todas las complejidades de la expresión regular, pero necesitaba generar algunos errores si había tokens malos, lo que no funcionó.
Pero en términos de hacer un regex y un ciclo de reemplazo razonable, esta es la respuesta que obtuve (con un poco de ayuda de Google y la respuesta existente, incluido el comentario de Sean Bright sobre cómo usar el grupo (1) frente a grupo()):
private static Pattern tokenPattern = Pattern.compile("\\{([^}]*)\\}");
public static String process(String template, Map<String, Object> params) {
StringBuffer sb = new StringBuffer();
Matcher myMatcher = tokenPattern.matcher(template);
while (myMatcher.find()) {
String field = myMatcher.group(1);
myMatcher.appendReplacement(sb, "");
sb.append(doParameter(field, params));
}
myMatcher.appendTail(sb);
return sb.toString();
}
Dónde doParameter obtiene el valor del mapa y la convierte en una cadena y lanza una excepción si no está allí.
Tenga en cuenta que también cambié el patrón para encontrar llaves vacías (es decir {}), ya que es una condición de error comprobada explícitamente.
EDIT:
Tenga en cuenta que appendReplacement no es independiente del contenido de la cadena. Según los javadocs, reconoce $ y la barra diagonal inversa como un carácter especial, así que agregué algunos de escape para manejar eso al ejemplo anterior. No se hace de la manera más consciente del rendimiento, pero en mi caso no es lo suficientemente grande como para intentar micro-optimizar las creaciones de cuerdas.
Gracias al comentario de Alan M, esto puede hacerse aún más simple para evitar los problemas de carácter especial de appendReplacement.
try http://github.com/niesfisch/tokenreplacer/ – Marcel