Спасибо всем за ответы!
Ответ Gizmo был определенно из коробки и отличным решением, но, к сожалению, не уместным, поскольку формат не может быть ограничен тем, что делает класс Formatter в этом случае.
Адам Пейнтер действительно понял суть дела, с правильным образцом.
У Питера Никса и Шона Брайта был отличный обходной путь, чтобы избежать всех сложностей регулярного выражения, но мне нужно было поднять некоторые ошибки, если были плохие токены, чего не произошло.
Но с точки зрения выполнения регулярных выражений и разумного цикла замены, это ответ, который я придумал (с небольшой помощью от Google и существующим ответом, включая комментарий Шона Брайта о том, как использовать group (1) против группа ()):
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();
}
Где doParameter получает значение из карты, преобразует его в строку и выдает исключение, если его там нет.
Обратите внимание, что я изменил шаблон, чтобы найти пустые скобки (т. Е. {}), Так как это условие ошибки, явно проверенное.
EDIT: Обратите внимание, что appendReplacement не зависит от содержимого строки. Согласно javadocs, он распознает $ и обратную косую черту как специальный символ, поэтому я добавил некоторые экранирующие символы для обработки этого в приведенном выше примере. Не сделано с максимальной эффективностью, но в моем случае это не такая уж большая проблема, чтобы стоить пытаться микрооптимизировать создание струн.
Благодаря комментарию Алана М, это можно сделать еще проще, чтобы избежать проблем с специальными символами appendReplacement.