Java matcher, как динамически заменять группы в зависимости от их значения

Для быстрого примера у меня есть следующая строка:

String s = "hey.there.man.${a.a}crazy$carl${a.b}jones

У меня также есть следующий метод:

private String resolveMatchedValue(String s) {
    if(s.equals("a.a")) {
           return "A";
    else if(s.equals("a.b")) { 
           return "Wallet";
    else if(.....
    ....
 }

Мой образец был бы

 Pattern pattern = Pattern.compile("\\$\\{(.*?)\\}");

Поэтому для каждой подстроки в s, которая соответствует ${.*}, я хочу, чтобы был вызов метода resolveMatchedValue, и его следует заменить этим. Так что в идеале после процесса регулярного выражения должно быть

 s = "hey.there.man.Acrazy$carl$Walletjones

Я просмотрел аналогичные решения, но ничего, что динамически заменяло бы совпадающие значения на основе совпадающего значения, и не смог заставить его работать

редактировать: используя java8


person yoplay one    schedule 13.05.2018    source источник
comment
Согласно коду, вывод не должен быть "hey.there.man.Acrazy$carlWalletjones"?   -  person mark42inbound    schedule 14.05.2018


Ответы (1)


Чтобы захватить только нужные символы, вы должны исключить правую фигурную скобку из своей группы [^}]+. На самом деле лучше просто включить конкретный шаблон, который вы ищете, чтобы отловить ошибки на ранней стадии:

Pattern pattern = Pattern.compile("\\$\\{([a-z]\\.[a-z]+)\\}");

Метод Matcher.replaceAll​(Function<MatchResult,String> replacer) предназначен для того, чтобы делать именно то, о чем вы просите. Функция, переданная методу, получает каждое совпадение и возвращает строку для ее замены.

В твоем случае:

pattern.matcher(input).replaceAll(mr -> resolveMatchedValue(mr.group(1)));

Вернет строку со всеми замененными подстроками, соответствующими вашему шаблону.

Вот рабочий пример, который просто прописывает поля:

System.out.println(Pattern.compile("\\$\\{([[a-z]\\.[a-z])\\}")
    .matcher("hey.there.man.${a.a}crazy$carl${a.b}jones")
    .replaceAll(mr -> mr.group(1).toUpperCase()));

До Java 9 эквивалент:

StringBuffer result = new StringBuffer();
while (matcher.find()) {
    matcher.appendReplacement(result, resolvedMatchedValue(matcher.group(1)));
}
matcher.appendTail(result);

После чего result.toString() содержит новую строку.

person sprinter    schedule 13.05.2018
comment
Спасибо за это, к сожалению, я заблокирован на Java 8 - person yoplay one; 14.05.2018
comment
@yoplayone Это было бы полезно иметь в исходном вопросе. Я предоставлю альтернативу до 9. - person sprinter; 14.05.2018