Я использую 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?
В настоящее время вы полностью соглашаетесь со всей строкой (что-либо + 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.
Ваше регулярное выражение .*(<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
matches()
проверяет, может ли регулярное выражение сопоставлять всю строку, и если это так, то эта строка будет использоваться Matcher, который не оставляет ничего для повторения. Но даже если вы не будете использовать всю строку с помощью метода matches()
вы сделаете это в первом find()
из-за жадности. .*
. Так что удалите их .*
Из начала и конца вашего регулярного выражения. Также избавьтесь от метода matches()
или замените его на find()
(а затем вызовите reset()
для matcher, чтобы сбросить курсор при запуске).
вам нужно изменить ваше регулярное выражение на "\<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));
}
matches()
иfind()
. Обычно вы либо используете одно, либо другое, они делают разные вещи: проверка или извлечение. В коде в вопросеmatches()
потребляет всю строку, поэтомуfind()
пытается начать с самого конца ввода.