RegExp可以在JS和PHP中工作,但不能在Java中工作



我有一个正则表达式来从HTML源代码中提取id和标签。可以在此处找到

正如你所看到的,它工作得很好,速度也很快,但当我用相同的源代码在java中尝试这个regexp时,它是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) + ")");
}

由于子表达式(?:.*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的危险之一:)

最后,来自你们大学信息学系的一位工作人员的问候:)

相关内容

最新更新