RegExp работает в JS и PHP, но не в Java - PullRequest
0 голосов
/ 22 января 2019

У меня есть регулярное выражение для извлечения идентификатора и метки из исходного кода HTML. Его можно найти ЗДЕСЬ .

Как вы можете видеть, он работает нормально и быстро, но когда я пробую это регулярное выражение в Java с тем же исходным кодом, он 1. Принимает навсегда и 2. соответствует только одной строке (от первой a до последней a - это один матч).

Я пробовал с включенным и выключенным флагом Multiline, но без разницы. Я не понимаю, как регулярное выражение может работать везде, но в Java. Есть идеи?

private static final String COURSE_REGEX = "<a class=\"list-group-item list-group-item-action \" href=\"https:\\/\\/moodle-hs-ulm\\.de\\/course\\/view\\.php\\?id=([0-9]*)\"(?:.*\\s){7}<span class=\"media-body \">([^<]*)<\\/span>";

Pattern pattern = Pattern.compile(COURSE_REGEX, Pattern.MULTILINE);
Matcher matcher = pattern.matcher(sourceCode);
List<String> courses = new ArrayList<>();

while(matcher.find() && matcher.groupCount() == 2){
    courses.add(matcher.group(1) + "(" + matcher.group(2) + ")");
}

1 Ответ

0 голосов
/ 22 января 2019

Ваше регулярное выражение сталкивается с катастрофическим возвратом из-за огромного числа возможных перестановок, которые необходимо проверить подвыражению (?:.*\s){7} (поскольку . также может совпадать с пробелами). Java прерывает попытку сопоставления после определенного количества шагов (не знаю, сколько, конечно,> 1.000.000). PHP или JS могут быть не такими осторожными.

Если вы упростите эту часть своего регулярного выражения до .*?, вы получите совпадения:

"(?s)<a class=\"list-group-item list-group-item-action \" href=\"https://moodle-hs-ulm\\.de/course/view\\.php\\?id=([0-9]*)\".*?<span class=\"media-body \">([^<]*)</span>"

Обратите внимание, что вам нужен флаг DOTALL ((?s), поэтому . может совпадать с новой строкой) вместо флага MULTILINE, который изменяет поведение якорей ^ и $ (ни один из которых ваше регулярное выражение использует).

Также обратите внимание, что вам не нужно экранировать косую черту в регулярном выражении Java.

Это решение не очень надежно, потому что .*? довольно неопределенно. Я полагаю, ваша предыдущая попытка (?:.*\\s){7} могла быть рассчитана не более чем на 7 строк текста? В этом случае вы можете использовать (?:(?!</a>).)*, чтобы не переходить к следующему тегу <a>. Это одна из опасностей парсинга HTML с помощью регулярных выражений:)

Наконец, привет от сотрудника факультета информатики в вашем университете:)

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