RegExp可在JS和PHP中运行,但不适用于Java

时间:2019-01-22 10:10:46

标签: javascript java php regex

我有一个正则表达式可以从HTML源代码中提取ID和标签。可以找到HERE

如您所见,它工作正常且速度很快,但是当我在Java中使用相同的源代码尝试此正则表达式时,它1.永远存在,并且2.仅匹配一个字符串(从第一个a到最后a是一场比赛。

我尝试了Multiline标志的开启和关闭,但没有区别。我不明白除了Java,regexp如何可以在任何地方工作。有什么想法吗?

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 :(得分:2)

您的正则表达式遇到catastrophic backtracking,因为子表达式(?:.*\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标志,它会更改{{1} }和^锚点(您的正则表达式均未使用)。

还请注意,您无需在Java正则表达式中转义斜杠。

此解决方案不是很可靠,因为$不太明确。我想您先前尝试的.*?可能被设计为匹配不超过7行文本?在这种情况下,您可以使用(?:.*\\s){7}来确保您不会越过下一个(?:(?!</a>).)*标签。这是用正则表达式解析HTML的危险之一:)

最后,您大学的信息学系职员的问候:)