Примените функцию к строке замены при сопоставлении с регулярным выражением в Java - PullRequest
0 голосов
/ 28 февраля 2011

Я хотел бы заменить некоторые шаблоны в строке на вызов функции для обнаруженных групп.

Более конкретно, я хотел бы, например, преобразовать

String input = "normal <upper> normal <upper again> normal";

в

String output = "normal UPPER normal UPPER AGAIN normal";

Регулярное выражение \<(.*?)\>" должно обнаружить шаблон, который я хочу преобразовать, но с использованием

output = input.replaceAll("\\<(.*?)\\>", "$1".toUpperCase());

не работает, потому что логически он помещает $1 в верхний регистр, то есть ничего не происходит, прежде чем обрабатывать его внутри метода.
Кроме того, метод, который я хочу применить, должен вызываться со строкой замены в качестве аргумента; таким образом, «неправильный наивный путь» был бы чем-то вроде

output = input.replaceAll("\\<(.*?)\\>", transform("$1"));

Вы знаете какой-нибудь трюк, чтобы сделать это?

Ответы [ 3 ]

5 голосов
/ 28 февраля 2011

Идиоматический способ сделать это немного многословно:

Matcher m = Pattern.compile("\\<(.*?)\\>").matcher(input);
StringBuffer b = new StringBuffer();
while (m.find()) {
    m.appendReplacement(b, transform(m.group());
}
m.appendTail(b);
output = b.toString();
1 голос
/ 01 марта 2011
Pattern p = Pattern.compile("<([^<>]+)>");
Matcher m = p.matcher(input);
StringBuffer sb = new StringBuffer();
while (m.find()) {
    m.appendReplacement(sb, "");
    sb.append(transform(m.group(1));
}
m.appendTail(sb);
output = sb.toString();

Основным улучшением по сравнению с ответом @ axtavt является двухэтапный процесс добавления.

appendReplacement() обрабатывает замещающую строку в поисках знаков доллара (которые указывают на групповые ссылки) и обратной косой черты (которые используются для экранирования знаков доллара и обратной косой черты). Но любые знаки доллара в наших замещающих строках должны рассматриваться буквально; обращение с ними как с групповыми ссылочными символами приведет к выводу мусора или исключениям времени выполнения. Поэтому мы отключаем его, передавая пустую строку в appendReplacement() и добавляя фактическую замену в StringBuffer сами.

Примечание: метод quoteReplacment(), о котором я упоминал в комментарии к другому ответу, тоже подойдет. Такой подход возможен, потому что мы выполняем цикл вручную, а не вызываем replaceAll() или replaceFirst(), и он более понятен (IMO) и более эффективен.

1 голос
/ 01 марта 2011

Пример показан здесь

Его печальная Java заставляет вас создавать отдельный буфер и создавать его с помощью m.find () только для того, чтобы переназначить его во входную строку.

В Perl все сделано внутри движка: $str =~ s/<(.*?)>/'<'.upper($1).'>'/seg; но это только perl, загадка для себя.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...