2015-02-07 6 views
0

Я пытаюсь соответствовать повторяющимся группам с Java:Как сопоставить вложенные повторяющиеся группы с регулярным выражением в Java?

String s = "The very first line\n" 
     + "\n" 
     + "AA (aa)\n" 
     + "BB (bb)\n" 
     + "CC (cc)\n" 
     + "\n"; 

Pattern p = Pattern.compile(
     "The very first line\\s+" 
     + "((?<gr1>[a-z]+)\\s+\\((?<gr2>[^)]+)\\)\\s*)+", 
     Pattern.DOTALL | Pattern.CASE_INSENSITIVE); 

Matcher m = p.matcher(s); 

if (m.find()) { 
    for (int i = 0; i <= m.groupCount(); i++) { 
     System.out.println("group #" + i + ": [" + m.group(i).trim() + "]"); 
    } 
    System.out.println("group gr1: [" + m.group("gr1").trim() + "]"); 
    System.out.println("group gr2: [" + m.group("gr2").trim() + "]"); 
} 

Проблема с повторяющимися группами: хотя регулярное выражение соответствует всему текстовому блоку (см group #0 в выходном примере ниже), при извлечении групп #2 и #3 (или по имени, а также - gr1/gr2) он возвращает только последний матч (CC/cc) и пропускает предыдущие (AA/aa и BB/bb)

group #0: [The very first line 

AA (aa) 
BB (bb) 
CC (cc)] 
group #1: [CC (cc)] 
group #2: [CC] 
group #3: [cc] 
group gr1: [CC] 
group gr2: [cc] 

Есть ли способ решить это?

редактировать:The very first line в шаблоне как строки идентификации - см комментарий к ответу на gknicker ниже действующей

ответ

1

Похоже, что вы хотели ваш шаблон, чтобы соответствовать не входную строку целиком, а только отдельные повторяющиеся разделы. Если это правда, ваша картина будет выглядеть так:

Pattern p = Pattern.compile(
     "((?<gr1>[a-z]+)\\s+\\((?<gr2>[^)]+)\\))", 
     Pattern.CASE_INSENSITIVE); 

Тогда в этом случае будет иметь while цикл, чтобы найти каждый матч:

Matcher m = p.matcher(s); 

    while (m.find()) { 
     System.out.println("group gr1: [" 
      + m.group("gr1").trim() + "]"); 
     System.out.println("group gr2: [" 
      + m.group("gr2").trim() + "]"); 
    } 

Но если вам нужен весь матч, вы, вероятно, должно использовать две модель, как это:

String s = "The very first line\n" 
     + "\n" 
     + "AA (aa)\n" 
     + "BB (bb)\n" 
     + "CC (cc)\n" 
     + "\n"; 

    Pattern p = Pattern.compile(
     "The very first line\\s+(([a-z]+)\\s+\\(([^)]+)\\)\\s*)+", 
     Pattern.CASE_INSENSITIVE); 

    Pattern p2 = Pattern.compile(
     "((?<gr1>[a-z]+)\\s+\\((?<gr2>[^)]+)\\))", 
     Pattern.CASE_INSENSITIVE); 

    Matcher m = p.matcher(s); 
    while (m.find()) { 
     Matcher m2 = p2.matcher(m.group()); 
     while (m2.find()) { 
      System.out.println("group gr1: [" 
       + m2.group("gr1").trim() + "]"); 
      System.out.println("group gr2: [" 
       + m2.group("gr2").trim() + "]"); 
     } 
    } 
+0

Спасибо за предложение, но я использую «самый первую строку» в виде строки ориентации - текст Я пытаюсь соответствовать содержит несколько разделов, имеющую такую ​​репутацию (что соответствует той же схеме). Если бы я «просто» соответствовал gr1 и gr2, тогда мне нужно было бы извлечь блок, который мне нужен, прежде чем пытаться его сопоставить, иначе я получаю неправильные результаты. – Laimoncijus

+0

См. Мое редактирование для альтернативного решения с двумя шаблонами. – gknicker

Смежные вопросы