检查字符串是否为有效URL的最佳正则表达式是什么?

1038

如何检查给定的字符串是否是有效的URL地址?

我对正则表达式的了解很基础,并不能让我从已经在网上看到的成百上千个正则表达式中进行选择。


45
只翻译内容:任何URL还是只有HTTP?例如,mailto:me@example.com算作URL吗?还是像AIM聊天链接这样的也算? - Mecki
6
如果一个URL没有以“http(等等)”开头,你怎么能把它与其他任意带有点的字符串区分开来?比如“MyClass.MyProperty.MyMethod”或者“I sometimes miss the spacebar. Is this a problem?” - Tomalak
15
微软有一个正则表达式页面,其中包括了一个用于URL的表达式。这是个不错的起点:http://msdn.microsoft.com/en-us/library/ff650303.aspx。 注意:上述页面已过时,但表格中的表达式基本仍然有效供参考。 建议使用的URL表达式(对我来说也非常好用)是: "^(ht|f)tp(s?)://0-9a-zA-Z(:(0-9))(/?)([a-zA-Z0-9-.?,'/\+&%$#_])?$" - CMH
65个回答

20

非验证的URI参考解析器

供参考,这是IETF规范:(TXT | HTML)。特别是,附录B. 使用正则表达式解析URI参考演示了如何解析有效的正则表达式。它被描述为:

一个非验证的URI参考解析器的示例,它将接受任何给定的字符串并提取URI组件。

这是他们提供的正则表达式:

^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?

就像其他人说的那样,最好还是把这个交给你已经在使用的库/框架来处理。

18
完全没有用。有人能展示一个这个正则表达式不匹配的字符串吗?( "#?#?#" 和 "<<<>>>" 都匹配。这些是什么类型的URI?) - Alex D
4
@AlexD 不要向我抱怨。这是统一资源标识符的官方规范。如果你不喜欢,可以向IETF提出建议。 - Hank Gay
1
@AlexD 我认为这些可能被视为“相对引用”。请参阅RFC 3986,第4.2节。 - andyg0808
3
@andyg0808,你可能是对的,但事实仍然是这个正则表达式几乎可以匹配任何字符串。 - Alex D
3
这不是一个好答案,因为它并没有按照问题要求进行验证,而是在解析。这是两个不同的功能。如果你给这个正则表达式无用的内容,它会尝试去解析它。如果URL不合法,那么解析也不能保证能够工作。 - Evan Carroll
显示剩余2条评论

13

对我来说,最好的URL正则表达式是:

"(([\w]+:)?//)?(([\d\w]|%[a-fA-F\d]{2,2})+(:([\d\w]|%[a-fA-f\d]{2,2})+)?@)?([\d\w][-\d\w]{0,253}[\d\w]\.)+[\w]{2,4}(:[\d]+)?(/([-+_~.\d\w]|%[a-fA-f\d]{2,2})*)*(\?(&?([-+_~.\d\w]|%[a-fA-f\d]{2,2})=?)*)?(#([-+_~.\d\w]|%[a-fA-f\d]{2,2})*)?"

这似乎在接受的域名数量方面有限制? - rektide
2
谢谢!这是在iOS上为我工作的转义版本:(([\\w]+:)?//)?(([\\d\\w]|%[a-fA-f\\d]{2,2})+(:([\\d\\w]|%[a-fA-f\\d]{2,2})+)?@)?([\\d\\w][-\\d\\w]{0,253}[\\d\\w]\\.)+[\\w]{2,4}(:[\\d]+)?(/([-+_~.\\d\\w]|%[a-fA-f\\d]{2,2})*)*(\\?(&?([-+_~.\\d\\w]|%[a-fA-f\\d]{2,2})=?)*)?(#([-+_~.\\d\\w]|%[a-fA-f\\d]{2,2})*)? - James Kuang
1
这个正则表达式只匹配长度不超过4个字符的后缀,并且无法匹配IP地址(v4和v6)、本地主机以及带有外语字符的域名。我建议您至少编辑包含大小范围并将\w替换为\p{L} - ndm13
不适用于 http://something.co.uk。 - Beki

12

这里有一个良好的规则适用于所有可能情况:端口、参数等等。

/(https?:\/\/(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9])(:?\d*)\/?([a-z_\/0-9\-#.]*)\??([a-z_\/0-9\-#=&]*)/g

请检查:www.ankit.com - Ankit Vishwakarma
适用于这些变体: https://www.domainname.com http://www.domainname.com http://domainname.com https://domainname.com https://www.domainname.com/ http://www.domainname.com/ http://domainname.com/ https://domainname.com/ https://www.domainname.com/inner-page http://www.domainname.com/inner-page http://domainname.com/inner-page https://domainname.com/inner-page https://www.domainname.com/inner-page/ http://www.domainname.com/inner-page/ http://domainname.com/inner-page/ https://domainname.com/inner-page/ - ApsaraAruna

11

我写了一个小的Groovy版本,可以运行

它匹配以下URL(对我来说足够好了)

public static void main(args) {
    String url = "go to http://www.m.abut.ly/abc its awesome"
    url = url.replaceAll(/https?:\/\/w{0,3}\w*?\.(\w*?\.)?\w{2,3}\S*|www\.(\w*?\.)?\w*?\.\w{2,3}\S*|(\w*?\.)?\w*?\.\w{2,3}[\/\?]\S*/ , { it ->
        "woof${it}woof"
    })
    println url 
}
http://google.com
http://google.com/help.php
http://google.com/help.php?a=5

http://www.google.com
http://www.google.com/help.php
http://www.google.com?a=5

google.com?a=5
google.com/help.php
google.com/help.php?a=5

http://www.m.google.com/help.php?a=5 (and all its permutations)
www.m.google.com/help.php?a=5 (and all its permutations)
m.google.com/help.php?a=5 (and all its permutations)

对于不以httpwww开头的任何URL,重要的是它们必须包含/?

我敢说这可以再微调一下,但它非常简短紧凑,已经做得很好了...因为你基本上可以将其分成三个部分:

查找任何以http开头的内容:

https?:\/\/w{0,3}\w*?\.\w{2,3}\S*

寻找以www开头的任何内容:

www\.\w*?\.\w{2,3}\S*

或者找到任何必须以文本开头,然后是一个点,至少有2个字母,然后是一个?/的内容:

\w*?\.\w{2,3}[\/\?]\S*

它还匹配不合法的网址,例如:https://http://www.google.com - undefined

10

我无法找到我要寻找的正则表达式,所以我修改了一个正则表达式来满足我的要求,现在看起来似乎工作得很好。我的要求是:

这是我想出来的东西,欢迎提出建议:

@Test
    public void testWebsiteUrl(){
        String regularExpression = "((http|ftp|https):\\/\\/)?[\\w\\-_]+(\\.[\\w\\-_]+)+([\\w\\-\\.,@?^=%&amp;:/~\\+#]*[\\w\\-\\@?^=%&amp;/~\\+#])?";

        assertTrue("www.google.com".matches(regularExpression));
        assertTrue("www.google.co.uk".matches(regularExpression));
        assertTrue("http://www.google.com".matches(regularExpression));
        assertTrue("http://www.google.co.uk".matches(regularExpression));
        assertTrue("https://www.google.com".matches(regularExpression));
        assertTrue("https://www.google.co.uk".matches(regularExpression));
        assertTrue("google.com".matches(regularExpression));
        assertTrue("google.co.uk".matches(regularExpression));
        assertTrue("google.mu".matches(regularExpression));
        assertTrue("mes.intnet.mu".matches(regularExpression));
        assertTrue("cse.uom.ac.mu".matches(regularExpression));

        assertTrue("http://www.google.com/path".matches(regularExpression));
        assertTrue("http://subdomain.web-site.com/cgi-bin/perl.cgi?key1=value1&key2=value2e".matches(regularExpression));
        assertTrue("http://www.google.com/?queryparam=123".matches(regularExpression));
        assertTrue("http://www.google.com/path?queryparam=123".matches(regularExpression));

        assertFalse("www..dr.google".matches(regularExpression));

        assertFalse("www:google.com".matches(regularExpression));

        assertFalse("https://www@.google.com".matches(regularExpression));

        assertFalse("https://www.google.com\"".matches(regularExpression));
        assertFalse("https://www.google.com'".matches(regularExpression));

        assertFalse("http://www.google.com/path'".matches(regularExpression));
        assertFalse("http://subdomain.web-site.com/cgi-bin/perl.cgi?key1=value1&key2=value2e'".matches(regularExpression));
        assertFalse("http://www.google.com/?queryparam=123'".matches(regularExpression));
        assertFalse("http://www.google.com/path?queryparam=12'3".matches(regularExpression));

    }

1
这个匹配项包括 http/stackoverflow.com/h77ps://stackoverflow.com///stackoverflow.com/ - TiberiumFusion
1
http/stackoverflow.com/ 是一个有效的相对URL,//stackoverflow.com/ 是一个没有特定协议的有效URL,h77ps情况有问题。 - dkellner
感谢反馈。我相信这里的意图是不包括相对路径,所以你们两个都是正确的,这是一个有效的相对URL,但我们的正则表达式不应该匹配它们。 我们需要改进正则表达式 :) - thermz

9
        function validateURL(textval) {
            var urlregex = new RegExp(
            "^(http|https|ftp)\://([a-zA-Z0-9\.\-]+(\:[a-zA-Z0-9\.&amp;%\$\-]+)*@)*((25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9])\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[0-9])|localhost|([a-zA-Z0-9\-]+\.)*[a-zA-Z0-9\-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(\:[0-9]+)*(/($|[a-zA-Z0-9\.\,\?\'\\\+&amp;%\$#\=~_\-]+))*$");
            return urlregex.test(textval);
        }

匹配 http://site.com/dir/file.php?var=moo | ftp://user:pass@site.com:21/file/dir

不匹配 site.com | http://site.com/dir//


请注意,此正则表达式将匹配包含[空格]的URL。例如:http://www.goo gle.com将匹配。 - Ifch0o1
在调用此函数之前,请使用parse_url()。 - LifeInstructor
别忘了转义“/”和“?”,这是一个好习惯,可以使其在各种平台上兼容(根据我所知道的(这方面的知识不多))。 - Steve P

7

7
如果你真的在寻找完美匹配,你可能会在“一个好的 Url 正则表达式?”上找到它。
但是一个真正匹配所有可能域名并允许 RFC 规范允许的任何内容的正则表达式会非常冗长和难懂,相信我 ;-)

6
我希望这对你有所帮助...
^(http|https):\/\/+[\www\d]+\.[\w]+(\/[\w\d]+)?

6
这是一个从URL中提取不同部分的正则表达式: ^((?:(?:http | ftp | ws)s? | sftp):\/\/?)?([^:/\s.#?]+\.[^:/\s#?]+ | localhost)(:\d+)?((?:\/\w+)*\/)?([\w\-.]+[^#?\s]+)?([^#]+)?(#[\w-]*)?$ ((?:(?:http | ftp | ws)s? | sftp):\/\/?)?(第1组):提取协议
([^:/\s.#?]+\.[^:/\s#?]+ | localhost)(第2组):提取主机名
(:\d+)?(第3组):提取端口号
((?:\/\w+)*\/)?([\w\-.]+[^#?\s]+)?(第4和第5组):提取路径部分
([^#]+)?(第6组):提取查询部分
(#[\w-]*)?(第7组):提取哈希部分

对于上面列出的每个正则表达式部分,您可以删除末尾的?以强制匹配(或添加一个以使其变成可选项)。 您也可以删除正则表达式开头的 ^ 和结尾的 $,以便不必匹配整个字符串。

此处查看
注意:这个正则表达式并不是100%安全的,并且可能接受一些不一定有效的URL字符串,但确实验证了一些标准。它的主要目的是提取URL的不同部分而不是验证它们。

谢谢。对于这些答案,团队方法是最好的。希望在下一页链接的这篇文章指导下进行更新,并修订“不是100%安全”的部分。像99.9%这样的量化已经足够满足大多数读者了。:P - Laurie Stearn
好的模式。可能我们还可以添加“文件”。另外,有人可以为他的目的添加“wss”和其他协议。 - CoolMind

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