使用正则表达式匹配字符串中的多个URL

时间:2012-12-06 23:06:09

标签: java regex

我正在尝试使用此处的正则表达式匹配字符串中的网址:Regular expression to match URLs in Java

它适用于一个URL,但是当我在字符串中有两个URL时,它只匹配后者。

以下是代码:

Pattern pat = Pattern.compile(".*((https?|ftp|file)://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|])", Pattern.DOTALL);
Matcher matcher = pat.matcher("asdasd http://www.asd.as/asd/123 or http://qwe.qw/qwe");
// now matcher.groupCount() == 2, not 4

编辑:我尝试过的东西:

// .* removed, now doesn't match anything // Another edit: actually works, see below
Pattern pat = Pattern.compile("((https?|ftp|file)://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|])", Pattern.DOTALL);

// .* made lazy, still only matches one
Pattern pat = Pattern.compile(".*?((https?|ftp|file)://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|])", Pattern.DOTALL);

有什么想法吗?

1 个答案:

答案 0 :(得分:4)

这是因为.*贪婪。它将尽可能多地消耗(整个字符串),然后回溯。即它会一次丢弃一个字符,直到其余字符组成一个URL。因此,第一个URL已经匹配,但未被捕获。不幸的是,比赛不能重叠。修复应该很简单。删除模式开头的.*。然后你也可以从你的模式中删除外括号 - 不再需要捕获任何东西,因为整个匹配将是你正在寻找的URL。

Pattern pat = Pattern.compile("(https?|ftp|file)://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|]", Pattern.DOTALL);
Matcher matcher = pat.matcher("asdasd http://www.asd.as/asd/123 or http://qwe.qw/qwe");
while (matcher.find()) {
  System.out.println(matcher.group());
}

顺便说一句,matcher.groupCount()没有告诉你任何事情,因为它会为你提供模式中的组数,而不是目标字符串中的捕获数。这就是为什么你的第二种方法(使用.*?)没有帮助。模式中仍然有两个捕获组。在致电find或其他任何内容之前,matcher不知道它总共会发现多少次捕获。