匹配带有或不带有http://www的URL的正则表达式模式

36
我其实不太擅长使用正则表达式。 到目前为止,我一直在使用很多框架代码,但是我找不到一个能够匹配像http://www.example.com/etcetc这样的URL,并且还能够捕获像www.example.com/etcetcexample.com/etcetc这样的URL的框架代码。

这个问题可能会对你有所帮助。https://dev59.com/VHM_5IYBdhLWcg3w-4hg - Wiseguy
可能是重复的问题,参考链接:不包含http://www的url正则表达式 - Balanivash
前两个选项可以匹配,但是匹配你最后一个选项“example.com/etcetc”几乎是不可能的。你需要基本上匹配任何中间带有点的内容。 - Spudley
1
@Balanivash - 有点过分了,将其标记为一个被关闭的问题的重复。 - Spudley
就像我昨天回答这样的问题,但今天被要求标记为重复问题,所以我这样做了。 - Balanivash
一个经典问题是 *如何在Python中将URL字符串拆分为单独的部分?*(2009年)。 - Peter Mortensen
13个回答

54

为了匹配所有类型的URL,以下代码应该可行:

<?php
    $regex = "((https?|ftp)://)?"; // SCHEME
    $regex .= "([a-z0-9+!*(),;?&=$_.-]+(:[a-z0-9+!*(),;?&=$_.-]+)?@)?"; // User and Pass
    $regex .= "([a-z0-9\-\.]*)\.(([a-z]{2,4})|([0-9]{1,3}\.([0-9]{1,3})\.([0-9]{1,3})))"; // Host or IP address
    $regex .= "(:[0-9]{2,5})?"; // Port
    $regex .= "(/([a-z0-9+$_%-]\.?)+)*/?"; // Path
    $regex .= "(\?[a-z+&\$_.-][a-z0-9;:@&%=+/$_.-]*)?"; // GET Query
    $regex .= "(#[a-z_.-][a-z0-9+$%_.-]*)?"; // Anchor
?>

然后,检查正则表达式的正确方法如下:

<?php
   if(preg_match("~^$regex$~i", 'www.example.com/etcetc', $m))
      var_dump($m);

   if(preg_match("~^$regex$~i", 'http://www.example.com/etcetc', $m))
      var_dump($m);
?>

致谢: splattermania 在 PHP 手册中发表的评论:preg_match

regex101 中的正则表达式演示


2
在方法内部添加注释通常是代码异味的标志。但是,在正则表达式或复杂的SQL查询中添加注释是正确的做法。 - Toto
1
@Toto 我知道有争议,例如http://programmers.stackexchange.com/questions/1/comments-are-a-code-smell,但我真的无法认同除了注释与代码不匹配的情况外,注释是代码异味的概念。 - Patrick
2
嗨,由于类似 YouTube 的链接,我不得不在每个小写字母 a-z 旁边加上 A-Z。但是我仍然认为它非常好。 - merveotesi
4
我喜欢你以注释的方式分解它。这有点像正则表达式自助餐,你可以挑选自己想要的放在盘子里。 - Expedito
1
如果你说尝试一下,我肯定知道它会起作用,因为你不会犯错误 :) 。谢谢anuba,现在它可以工作了,这就是我问你的原因 :)。+1 - Scooter Daraf
显示剩余20条评论

20

这在我测试的所有情况下都有效:

$url_pattern = '/((http|https)\:\/\/)?[a-zA-Z0-9\.\/\?\:@\-_=#]+\.([a-zA-Z0-9\&\.\/\?\:@\-_=#])*/';

测试:

http://test.test-75.1474.stackoverflow.com/
https://www.stackoverflow.com
https://www.stackoverflow.com/
http://wwww.stackoverflow.com/
http://wwww.stackoverflow.com


http://test.test-75.1474.stackoverflow.com/
http://www.stackoverflow.com
http://www.stackoverflow.com/
stackoverflow.com/
stackoverflow.com

http://www.example.com/etcetc
www.example.com/etcetc
example.com/etcetc
user:pass@example.com/etcetc

example.com/etcetc?query=aasd
example.com/etcetc?query=aasd&dest=asds

https://dev59.com/3Gw15IYBdhLWcg3wv-NM
https://dev59.com/3Gw15IYBdhLWcg3wv-NM/

每个有效的互联网URL至少有一个点,因此上述模式将尝试找到由点链接的至少两个字符串,并具有URL可能具有的有效字符。


2
简化了这个正则表达式:/^[a-z0-9./?:@\-_=#]+\.([a-z0-9./?:@\-_=#])*$/i - 方括号内的元字符不需要转义 - 去掉了前面的可选部分,因为在验证URL时不需要捕获值(在我的用例中不需要) - 使用大小写不敏感的修饰符简化模式,而不是在字符组中重复所有内容。 - staabm
另一个故障:上述正则表达式无法处理包含参数(因此包含 & 符号)的 URL。同时,编码的参数也不被支持 - 百分号(%)。 - staabm
1
/(http|https)://+[a-zA-Z0-9./?:@-=#]+.([a-zA-Z0-9&./?:@-=#])*/ 请在 (http|https):// 后使用 + 号代替 ? 号,因为 ? 号也会通过 http:/。这样,http:/yahoo.com 就是正确的,但实际上不是。加上 + 号就可以解决此问题。 - Roop Kumar
1
从原始模式中,我只用一个加号替换了最后一个 *,以避免像 word. 这样的字符串匹配表达式。只有像 word.com 这样的字符串应该匹配。 - Roger
最后,我发现将最后一个 * 替换为 {2,} 更好。 - Roger
这个字符串2020-08-06T16:26:23.561Z也会被传递。 - Awais Ayub

5
您可以在正则表达式后面加一个问号来使它成为条件语句,所以您需要使用:
http:\/\/(www\.)?

这将匹配任何具有http://www.或http://(没有www)的内容。

您可以使用替换方法来删除上述内容,从而获得域名。这取决于您需要域名的用途。


5
尝试这个: /^http:\/\/|(www\.)?[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/.*)?$/ 它完全符合人们的要求。
它可以带或不带 http://, https://, 和 www

3

使用:

/(https?://)?((?:(\w+-)*\w+)\.)+(?:[a-z]{2})(\/?\w?-?=?_?\??&?)+[\.]?([a-z0-9\?=&_\-%#])?/g

它匹配 something.com, http(s):// 或者 www。不过它不会匹配其它的 [something]:// 的 URL,但是对于我的用途来说这并不是必需的。

这个正则表达式可以匹配以下内容:

http://foo.co.uk/
www.regex.com/foo.html?q=bar$some=thi-ng,regex
regex.foo.com/blog

3

尝试使用以下代码:

.*([\w-]+\.)+[a-z]{2,5}(/[\w-]+)*

1

试试这个

$url_reg = /(ftp|https?):\/\/(\w+:?\w*@)?(\S+)(:[0-9]+)?(\/([\w#!:.?+=&%@!\/-])?)?/;

这个表达式适用于所有的网址,除了那些缺少 http://www. 的,例如 example.com/khafenxj。 - Edmund Rojas
有没有办法使“www.”部分也是可选的?我对正则表达式有一点了解,但我仍然觉得它很难读懂哈哈。 - Edmund Rojas
这应该不适用于任何缺少 http:// 的东西,或者任何缺少协议的东西。 - phant0m

1
我一直在使用以下内容,对于所有我的测试案例都有效,并修复了任何问题,例如在句号(end.)之前的句子末尾触发,或者存在单个字符缩写,例如“C.C. Plumbing”。
以下正则表达式包含多个{2,},表示前一个模式的两个或更多匹配。
((http|https)\:\/\/)?[a-zA-Z0-9\.\/\?\:@\-_=#]{2,}\.([a-zA-Z0-9\&\.\/\?\:@\-_=#]){2,}

匹配诸如但不限于以下URL:

不匹配非URL,例如但不限于以下内容:

  • C.C 水管工
  • 句子结尾的句号。
  • a.bx.y 这样的单字符。

请注意:由于上述原因,此正则表达式不会匹配任何单字符URL,例如:a.co,但如果前面有URL方案,如:http://a.co,则会匹配。


如果它只有 a.co 呢? - MAC

1
你可以尝试这个:

r"(http[s]:\/\/)?([\w-]+\.)+([a-z]{2,5})(\/+\w+)? "

选择:

  1. 可能以 http:// 或 https:// 开头(可选)

  2. 任何以点(.)结尾的内容(单词)

  3. 接着是 2 到 5 个小写字母 [a-z]

  4. 接着是 "/[任何内容]"(可选)

  5. 接着是空格


0

我在使用anubhava的答案时遇到了很多问题,因为最近的PHP允许在字符串中使用$,而preg匹配无法正常工作。

这是我使用的代码:

// Regular expression
$re = '/((https?|ftp):\/\/)?([a-z0-9+!*(),;?&=.-]+(:[a-z0-9+!*(),;?&=.-]+)?@)?([a-z0-9\-\.]*)\.(([a-z]{2,4})|([0-9]{1,3}\.([0-9]{1,3})\.([0-9]{1,3})))(:[0-9]{2,5})?(\/([a-z0-9+%-]\.?)+)*\/?(\?[a-z+&$_.-][a-z0-9;:@&%=+\/.-]*)?(#[a-z_.-][a-z0-9+$%_.-]*)?/i';
// Match all
preg_match_all($re, $blob, $matches, PREG_SET_ORDER, 0);
// Print the entire match result
var_dump($matches);
// The first element of the array is the full match

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接