我有一个正则表达式可以从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) + ")");
}
答案 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的危险之一:)
最后,您大学的信息学系职员的问候:)