Рекурсивная группа, захватывающая регулярное выражение с обратной ссылкой в ​​JAVA

Я пытаюсь рекурсивно записать несколько групп в строку, используя также обратную ссылку на группу в регулярном выражении. Несмотря на то, что я использую Pattern и Matcher и цикл while (matcher.find ()), он по-прежнему захватывает только последний экземпляр, а не все экземпляры. В моем случае единственными возможными тегами являются ‹sm›, ‹po›, ‹pof›, ‹pos›, ‹poi›, ‹pol›, ‹poif›, ‹poil›. Поскольку это теги форматирования, мне нужно захватить:

  1. любой текст за пределами тега (чтобы я мог отформатировать его как «обычный» текст, и я собираюсь сделать это, захватив любой текст перед тегом в одной группе, пока я захватываю сам тег в другой группе, и когда я перебираю вхождения я удаляю все, что было захвачено из исходной строки; если в конце у меня остался какой-либо текст, я форматирую это как "нормальный" текст)
  2. "имя" тега, чтобы я знал, как мне нужно форматировать текст внутри тега
  3. текстовое содержимое тега, которое будет отформатировано в соответствии с именем тега и связанными с ним правилами

Вот мой пример кода:

        String currentText = "the man said:<pof>“This one, at last, is bone of my bones</pof><poi>and flesh of my flesh;</poi><po>This one shall be called ‘woman,’</po><poil>for out of man this one has been taken.”</poil>";
        String remainingText = currentText;

        //first check if our string even has any kind of xml tag, because if not we will just format the whole string as "normal" text
        if(currentText.matches("(?su).*<[/]{0,1}(?:sm|po)[f|l|s|i|3]{0,1}[f|l]{0,1}>.*"))
        {                
            //an opening or closing tag has been found, so let us start our pattern captures
            //I am using a backreference \\2 to make sure the closing tag is the same as the opening tag
            Pattern pattern1 = Pattern.compile("(.*)<((sm|po)[f|l|s|i|3]{0,1}[f|l]{0,1})>(.*?)</\\2>",Pattern.UNICODE_CHARACTER_CLASS);
            Matcher matcher1 = pattern1.matcher(currentText);                
            int iteration = 0;
            while(matcher1.find()){
                System.out.print("Iteration ");
                System.out.println(++iteration);
                System.out.println("group1:"+matcher1.group(1));
                System.out.println("group2:"+matcher1.group(2));
                System.out.println("group3:"+matcher1.group(3));
                System.out.println("group4:"+matcher1.group(4));

                if(matcher1.group(1) != null && matcher1.group(1).isEmpty() == false)
                {
                    m_xText.insertString(xTextRange, matcher1.group(1), false);
                    remainingText = remainingText.replaceFirst(matcher1.group(1), "");
                }
                if(matcher1.group(4) != null && matcher1.group(4).isEmpty() == false)
                {
                    switch (matcher1.group(2)) {
                        case "pof": [...]
                        case "pos": [...]
                        case "poif": [...]
                        case "po": [...]
                        case "poi": [...]
                        case "pol": [...]
                        case "poil": [...]
                        case "sm": [...]
                    }
                    remainingText = remainingText.replaceFirst("<"+matcher1.group(2)+">"+matcher1.group(4)+"</"+matcher1.group(2)+">", "");
                }
            }

System.out.println выводится на мою консоль только один раз со следующими результатами:

Iteration 1:
  group1:the man said:<pof>“This one, at last, is bone of my bones</pof><poi>and flesh of my flesh;</poi><po>This one shall be called ‘woman,’</po>; 
  group2:poil
  group3:po
  group4:for out of man this one has been taken.”

Группу 3 следует игнорировать, единственными полезными группами являются 1, 2 и 4 (группа 3 является частью группы 2). Почему это захватывает только последний экземпляр тега «poil», тогда как предыдущие теги «pof», «poi» и «po» не захватываются?

Результат, который я хотел бы видеть, будет таким:

Iteration 1:
  group1:the man said:
  group2:pof
  group3:po
  group4:“This one, at last, is bone of my bones

Iteration 2:
  group1:
  group2:poi
  group3:po
  group4:and flesh of my flesh;

Iteration 3:
  group1:
  group2:po
  group3:po
  group4:This one shall be called ‘woman,’

Iteration 3:
  group1:
  group2:poil
  group3:po
  group4:for out of man this one has been taken.”

person JohnRDOrazio    schedule 17.08.2015    source источник


Ответы (1)


Я только что нашел ответ на эту проблему, ему просто нужен был не жадный квантификатор в первом захвате, как и в четвертой группе захвата. Это работает именно так, как нужно:

Pattern pattern1 = Pattern.compile("(.*?)<((sm|po)[f|l|s|i|3]{0,1}[f|l]{0,1})>(.*?)</\\2>",Pattern.UNICODE_CHARACTER_CLASS);
person JohnRDOrazio    schedule 17.08.2015
comment
Я думаю, вы можете ввести [flsi3] вместо [f | l | s | i | 3] и [fl] вместо [f | l] - person jairhumberto; 16.03.2019