Есть ли способ захватить каждую группу, если совпадают несколько вхождений? - PullRequest
9 голосов
/ 26 ноября 2010

Я не знаю, как объяснить проблему простым английским языком, поэтому я помогаю себе с примером регулярного выражения. У меня есть что-то похожее на это (пример довольно сильно упрощен):

((\\d+) - (\\d+)\n)+

Этот шаблон соответствует этим строкам сразу:

123 - 23
32 - 321
3 - 0
99 - 55

Шаблон содержит 3 группы: первая соответствует строке, 2-я соответствует первому числу в строке, а третья соответствует второму номеру в строке.

Есть ли возможность получить все эти цифры? У Matcher всего 3 группы. Первый возвращает 99 - 55, второй - 99, а третий - 55.

SSCCE:

class Test {
    private static final Pattern pattern = Pattern.compile("((\\d+) - (\\d+)\n)+");

    public static void parseInput(String input) {

        Matcher matcher = pattern.matcher(input);

        if (matcher.matches()) {

            for (int i = 0; i <= matcher.groupCount(); i++) {
                System.out.println("------------");
                System.out.println("Group " + i + ": " + matcher.group(i));
            }
            System.out.println();
        }

    }

    public static void main(String[] args) {
        parseInput("123 - 23\n32 - 321\n3 - 0\n99 - 55\n");
    }
}

Ответы [ 3 ]

8 голосов
/ 06 августа 2012

Еще одно замечание по поводу ответа Майка Карона: программа не будет работать, если вы просто замените «if» на «while» и используете «find» вместо «match».Вы также должны изменить регулярное выражение: последняя группа с «+» должна быть удалена, потому что вы хотите искать несколько вхождений этого шаблона, а не одно вхождение (..) + группы.

Для ясности, это последняя программа, которая работает:

class Test {
    private static final Pattern pattern = Pattern.compile("(\\d+) - (\\d+)\n");

    public static void parseInput(String input) {

        Matcher matcher = pattern.matcher(input);

        while (matcher.find()) {

            for (int i = 0; i <= matcher.groupCount(); i++) {
                System.out.println("------------");
                System.out.println("Group " + i + ": " + matcher.group(i));
            }
            System.out.println();
        }
    }

    public static void main(String[] args) {
        parseInput("123 - 23\n32 - 321\n3 - 0\n99 - 55\n");
    }
}

Она даст вам три группы для каждой строки, где первая группа - это целая строка, а две следующие группы содержат число.Это хороший учебник, который помог мне лучше понять его: http://tutorials.jenkov.com/java-regex/matcher.html

5 голосов
/ 26 ноября 2010

Если я не ошибаюсь (отличная возможность), то каждый раз, когда вы звоните matcher.matches(), он обновляется со следующим совпадением. Так по сути, измените if (matcher.matches()) на while (matcher.find()), и вы готовы к работе.

РЕДАКТИРОВАТЬ: На самом деле это не matches, это find, что делает это:

http://download.oracle.com/javase/7/docs/api/java/util/regex/Matcher.html#find%28%29

Вот пример его использования:

http://download.oracle.com/javase/tutorial/essential/regex/test_harness.html

2 голосов
/ 26 ноября 2010

Вы пытаетесь сопоставить каждую строку отдельно?

Удалите +, чтобы соответствовать только одной строке и измените:

   if (matcher.matches()) {

до:

   while (matcher.matches()) {

, и он будет зацикливаться один раз для каждого совпадения и автоматически пропускает любой несоответствующий текст между совпадениями.

Обратите внимание, что matcher.group (0) возвращает все совпадение. Актуальные группы начинаются с 1.

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