21 сентября 2011 г.

Java regexp: при использовании appendReplacement или replaceAll внезапно происходит Illegal group reference

Это странное поведение некоторых методов regexp с некоторыми случайными параметрами одно время убило мне пару часов отладки. Сам виноват, ибо проглядел в доках указание на специальное значение символов '$' и '\'. Не подумал, что из-за них может выкидываться java.lang.IllegalArgumentException, про который нет ничего в явадоках этих методов.
Как словить ошибку: использовать эти символы при замене.
String string = "Price: #PRICE#";
String price = "$more";
string = string.replaceAll("#PRICE#", price);
Что имеем:
java.lang.IllegalArgumentException: Illegal group reference
Если использовать, например,
String price = "$10";
, то получим
java.lang.IndexOutOfBoundsException: No group 1

Понятно, что в данном случае лучше всего использовать MessageFormat, но речь не об этом. Способ намбер ту схематично выглядит так:
String string = "Price: #PRICE#";
Matcher variableMatcher = variablePattern.matcher( string );
StringBuffer result = new StringBuffer(64);
while (variableMatcher.find())
{
 String var = variableMatcher.group(1); // if "PRICE"...
 String price = "$more";
 variableMatcher.appendReplacement(result, price);
}
variableMatcher.appendTail(result);
string = result.toString();
Решение — экранирование спецсимволов в строках, КОТОРЫМИ заменяем. Можно не руками, для этого есть специальный метод:
price = Matcher.quoteReplacement(price);
, им надо воспользоваться до вызова replaceAll/appendReplacement/...
Это всё.

Комментариев нет:

Отправить комментарий