Java. Замена по регулярному выражению

323
07 декабря 2017, 00:23

Есть несколько паттернов, которые я объединяю через join("|").

Задача, каждый паттерн может удовлетворять N-количеству совпадений
Например: (и\\s*\\.*\\s*т\\s*\\.?\\s*д\\s*\\.)
Каждое совпадение забиваем в HashMap<String, String>, где <Хэш, Совпадение>
Каждое совпадение заменить на хэш в исходной строке.

Проблема: Почему-то Matcher.find() делает только одну итерацию цикла и заменяет все паттерны через пайп | на один и то же хэш.

Что делать в таком случае, кроме как составлять вручную списки слов?

UPD

Упрощенный пример для данной задачи (https://ideone.com/d1UhRh):

import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.HashMap;
public class Main
{
   static void processString(String line)
   {
      Pattern p = Pattern.compile("(1\\%?|2|3|4)"); // 5 Вариантов паттернов для теста
      Matcher m = p.matcher(line);          // Естественно в реальной задаче намного больше
      HashMap<String, String> map = new HashMap<>();
      int i = 0;
      while (m.find()) {
        // Здесь я ожидаю 5 итераций для каждого вхождения 1, 1%, 2, 3, 4 и замены их на ААА1, ААА1%, ААА2 и т.д.
        // Эти вхождения добавить в HashMap (map) ниже
        i++;
         System.out.println("Нужно заменить " + m.group() + " на AAA" + i);
         // Добавить $1 в хэшмап !!
         // map.put(?)
         // То есть если я передаю все 5 паттернов, то в map должно быть 5 записей
         line = m.replaceAll("AAA$1");
      }
      System.out.println("\n\n" + line);
   }
   public static void main(String[] args)
   {
      processString(" 1  2  3  4  4  2  1%  1%  1  2  3 ");
   }
}

Результат:

AAA1 AAA1 AAA1 AAA1 AAA1 AAA1 AAA1 AAA1 AAA1 AAA1 AAA1

Ожидаемый результат:

AAA1 AAA2 AAA3 AAA4 AAA4 AAA2 AAA1% AAA1% AAA1 AAA2 AAA3

UPD 2
Добавил уточнение по вопросу по поводу HashMap

Answer 1

Поиск производится только один раз потому как Matcher.replaceAll заменяет все вхождения в исходной строке, после чего перезапускает matcher:

This method first resets this matcher. It then scans the input sequence looking for matches of the pattern.

Если нужно заменять вхождения по очереди, то можно воспользоваться Matcher.appendReplacement и Matcher.appendTail:

StringBuffer sb = new StringBuffer();
while (m.find()) {
    i++;
    m.appendReplacement(sb, "AAA"+i);
}
m.appendTail(sb);
System.out.println("\n\n" + sb);

Если нужно сохранять вхождения в Map, то можно обрабатывать каждое и запоминать хэши:

HashMap<String, String> map = new HashMap<String,String>();
StringBuffer sb = new StringBuffer();
while (m.find()) {      
    String group = m.group();
    String replacement;
    if(map.containsKey(group)) {
       //уже есть хэш
       replacement = map.get(group);
    } else {
       //создаем  и запоминаем новый хэш
       i++;
       replacement = "AAA"+i;
       map.put(group, replacement);
    }
    m.appendReplacement(sb, replacement);
}
m.appendTail(sb);

Количество итераций при этом будет равно количеству вхождений, а не количеству уникальных вхождений.

Здесь для удобства используется отображение Совпадение -> Хэш, а не Хэш -> Совпадение как в вопросе, но при желании можно параллельно вести и обратное отображение.

Добавьте обработку того, что 1 и 1% сводятся к одному хэшу по вкусу. Либо используйте выражение (1|2|3|4), а проценты оставляйте без изменений.

Пример на Ideone.

READ ALSO
Алгоритм формирования списка

Алгоритм формирования списка

мне нужно придумать алгоритм, который будет формировать плейлист из треков длительностью 1 частреки находятся в 2 разных папках

216
Как моментально отследить кнопку Power на android?

Как моментально отследить кнопку Power на android?

Добрый день, как можно моментально отследить кнопку Power? В этом примере кода она срабатывает только после того, как пройдет некоторое время...

216
Удалить все вхождения с помощью StringBuffer

Удалить все вхождения с помощью StringBuffer

Есть массив слов и в каждом слове от 2 до 10 строчных латинских буквС помощью StringBuffer удалить все вхождения "th"

249
Selenium WebDriver + Jsoup

Selenium WebDriver + Jsoup

Нужно вытащить расписание вот с этой страницы: http://ruzspbstu

258