Java regexp matcher - несколько групп

1

Я использую Pattern и Matcher для создания regexp, который будет извлекать 6 значений из тегов li, которые у меня есть ниже:

 <ul class="Bold">                                <li class="ball-orange">2</li>                                <li class="ball-orange">10</li>                                <li class="ball-orange">11</li>                                <li class="ball-orange">15</li>                                <li class="ball-orange">22</li>                                <li class="ball-orange">39</li>                            </ul>

Т.е. результатом регулярного выражения должны быть группы с 2, 10, 11, 15, 22, 39.

У меня есть следующий код:

Pattern numbersPattern = Pattern.compile(".*(<li class=\"ball-orange\">([0-9]{1,2})</li>).*");
Matcher matchNumbers = numbersPattern.matcher(mainBlock);//mainBlock is the string I quoted above which contains all the li's
System.out.println("Numbers Match? " + matchNumbers.matches());//this returns true
System.out.println(matchNumbers.group(2));//returns 39, i.e. second group but for the last li

//this loop never gets entered!!!
while (matchNumbers.find()) {
    System.out.println("group 1: " + matcher.group(1));
    System.out.println("group 2: " + matcher.group(2));
    //System.out.println("group 3: " + matcher.group(3));
}

Таким образом, он соответствует самому последнему, как вы можете видеть из комментариев, но он не вводит цикл while (matchNumbers.find()). Т.е. я хочу (<li class=\"ball-orange\">([0-9]{1,2})</li>) найти 6 раз и выводить в цикле, но это не так.

Я следую здесь: http://tutorials.jenkov.com/java-regex/matcher.html#groups-inside-groups.

Почему цикл не вводится и как я могу сопоставить группы li?

Теги:

3 ответа

1
Лучший ответ

В настоящее время вы полностью соглашаетесь со всей строкой (что-либо + li + все), поэтому matches() == true. Если вы хотите все, просто удалите .* Детали, потому что .find() найдет ваш шаблон несколько раз, сначала в позиции ~ 25, а затем ~ 60 и т.д....:

    String mainBlock = "<ul class=\"Bold\">                                <li class=\"ball-orange\">2</li>                                <li class=\"ball-orange\">10</li>                                <li class=\"ball-orange\">11</li>                                <li class=\"ball-orange\">15</li>                                <li class=\"ball-orange\">22</li>                                <li class=\"ball-orange\">39</li>                            </ul>";
    Pattern listPattern = Pattern.compile("<li class=\"ball-orange\">([0-9]{1,2})</li>");
    Matcher matcher = listPattern.matcher(mainBlock);
    while (matcher.find()) {
        System.out.println("whole thing: " + matcher.group()); // or group(0)
        System.out.println("number: " + matcher.group(1));
    }

целая вещь: <li class= "ball-orange"> 2 </li>
номер 2
целая вещь: <li class= "ball-orange"> 10 </li>
номер: 10
все: <li class= "ball-orange"> 11 </li>
номер: 11
целая вещь: <li class= "ball-orange"> 15 </li>
номер: 15
целая вещь: <li class= "ball-orange"> 22 </li>
номер: 22
целая вещь: <li class= "ball-orange"> 39 </li>
номер: 39

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

  • 0
    Спасибо, но когда я пытаюсь именно это (удаление. *, Как у вас), это ничего не соответствует. «Соответствие номеров?» + MatchNumbers.matches () возвращает false.
  • 1
    Это потому, что шаблон не соответствует всей строке, и не должен, потому что вы ищете части. Прочитайте Javadoc для matches() и find() . Обычно вы либо используете одно, либо другое, они делают разные вещи: проверка или извлечение. В коде в вопросе matches() потребляет всю строку, поэтому find() пытается начать с самого конца ввода.
Показать ещё 3 комментария
2

Ваше регулярное выражение .*(<li class=\"ball-orange\">([0-9]{1,2})</li>).* Будет потреблять целую строку из-за .* начале и в конце. Если вы хотите ввести цикл, рассмотрите только часть (<li class=\"ball-orange\">([0-9]{1,2})</li>).

Или даже лучше вместо регулярного выражения использовать правильный инструмент: HTML-парсер, как jsoup:

String mainBlock = "<ul class=\"Bold\">                                <li class=\"ball-orange\">2</li>                                <li class=\"ball-orange\">10</li>                                <li class=\"ball-orange\">11</li>                                <li class=\"ball-orange\">15</li>                                <li class=\"ball-orange\">22</li>                                <li class=\"ball-orange\">39</li>                            </ul>";
Document doc = Jsoup.parse(mainBlock);
for (Element el : doc.select("li.ball-orange")){//pick all <li class="ball-orange"> tags
    System.out.println("li tag: " + el);
    System.out.println("value in li : " + el.text());
}

Вывод:

li tag: <li class="ball-orange">2</li>
value in li : 2
li tag: <li class="ball-orange">10</li>
value in li : 10
li tag: <li class="ball-orange">11</li>
value in li : 11
li tag: <li class="ball-orange">15</li>
value in li : 15
li tag: <li class="ball-orange">22</li>
value in li : 22
li tag: <li class="ball-orange">39</li>
value in li : 39
  • 0
    Спасибо, попробую Jsoup, похоже здесь хорошее решение. Я все еще хотел бы знать, как заставить регулярное выражение работать, хотя.
  • 0
    matches() проверяет, может ли регулярное выражение сопоставлять всю строку, и если это так, то эта строка будет использоваться Matcher, который не оставляет ничего для повторения. Но даже если вы не будете использовать всю строку с помощью метода matches() вы сделаете это в первом find() из-за жадности. .* . Так что удалите их .* Из начала и конца вашего регулярного выражения. Также избавьтесь от метода matches() или замените его на find() (а затем вызовите reset() для matcher, чтобы сбросить курсор при запуске).
Показать ещё 2 комментария
-2

вам нужно изменить ваше регулярное выражение на "\<li class=\"ball-orange\"\>\d{1,2}\</li\>" использовать \d вместо [0-9]

Pattern numbersPattern = Pattern.compile("\<li class=\"ball-orange\"\>\d{1,2}\</li\>");
        Matcher matchNumbers = numbersPattern.matcher(mainBlock);//mainBlock is the string I quoted above which contains all the li's
        System.out.println("Numbers Match? " + matchNumbers.matches());//this returns true
        System.out.println(matchNumbers.group(2));//returns 39, i.e. second group but for the last li

        //this loop never gets entered!!!
        while (matchNumbers.find()) {
            System.out.println("group 1: " + matcher.group(1));
            System.out.println("group 2: " + matcher.group(2));
            //System.out.println("group 3: " + matcher.group(3));
        }
  • 0
    Вы были на правильном пути, отвечали на вопросы с объяснениями того, что вы изменили, как это не сработало и как это работает сейчас. Мне потребовалось несколько секунд, чтобы выявить различия, всегда указывать, что вы изменили при публикации кода, если он не совсем очевиден.
  • 0
    Извините но я спешил

Ещё вопросы

Сообщество Overcoder
Наверх
Меню