Спасибо всем за ответы!
Ответ Gizmo определенно был вне коробки и отличное решение, но, к сожалению, не уместно, поскольку формат не может быть ограничен тем, что делает класс Formatter в этом случае.
Адам Пейнтер действительно добрался до сути дела, с правильным рисунком.
У Питера Никса и Шона Брайта было большое обходное решение, чтобы избежать всех сложностей регулярного выражения, но мне нужно было поднять некоторые ошибки, если были плохие жетоны, чего не делали.
Но с точки зрения как регулярного выражения, так и разумного цикла замены это ответ, который я получил (с небольшой помощью от Google и существующего ответа, включая комментарий Шона Брайта о том, как использовать группу (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.
try http://github.com/niesfisch/tokenreplacer/ – Marcel