正则表达式用于匹配URL,其中方案是可选的(不包括“http”)

27
我正在使用以下正则表达式来匹配URL:
$search  = "/([\S]+\.(MUSEUM|TRAVEL|AERO|ARPA|ASIA|COOP|INFO|NAME|BIZ|CAT|COM|INT|JOBS|NET|ORG|PRO|TEL|AC|AD|AE|AF|AG|AI|AL|AM|AN|AO|AQ|AR|AS|AT|AU|au|AW|AX|AZ|BA|BB|BD|BE|BF|BG|BH|BI|BJ|BL|BM|BN|BO|BR|BS|BT|BV|BW|BY|BZ|CA|CC|CD|CF|CG|CH|CI|CK|CL|CM|CN|CO|CR|CU|CV|CX|CY|CZ|DE|DJ|DK|DM|DO|DZ|EC|EDU|EE|EG|EH|ER|ES|ET|EU|FI|FJ|FK|FM|FO|FR|GA|GB|GD|GE|GF|GG|GH|GI|GL|GM|GN|GOV|GP|GQ|GR|GS|GT|GU|GW|GY|HK|HM|HN|HR|HT|HU|ID|IE|IL|IM|IN|IO|IQ|IR|IS|IT|JE|JM|JO|JP|KE|KG|KH|KI|KM|KN|KP|KR|KW|KY|KZ|LA|LB|LC|LI|LK|LR|LS|LT|LU|LV|LY|MA|MC|MD|ME|MF|MG|MH|MIL|MK|ML|MM|MN|MO|MOBI|MP|MQ|MR|MS|MT|MU|MV|MW|MX|MY|MZ|NA|NC|NE|NF|NG|NI|NL|NO|NP|NR|NU|NZ|OM|PA|PE|PF|PG|PH|PK|PL|PM|PN|PR|PS|PT|PW|PY|QA|RE|RO|RS|RU|RW|SA|SB|SC|SD|SE|SG|SH|SI|SJ|SK|SL|SM|SN|SO|SR|ST|SU|SV|SY|SZ|TC|TD|TF|TG|TH|TJ|TK|TL|TM|TN|TO|R|H|TP|TR|TT|TV|TW|TZ|UA|UG|UK|UM|US|UY|UZ|VA|VC|VE|VG|VI|VN|VU|WF|WS|YE|YT|YU|ZA|ZM|ZW)([\S]*))/i";

但是有点混乱,因为它也匹配了"example.php",而我不想要这个。还有类似abc...test这样的情况。我希望它能匹配example.com,以及www.example.comhttp://example.com
只需要稍微调整一下末尾,但我不确定具体怎么做。(目前它没有检查任何域名后面的斜杠,而且只检查\S)
感谢您的时间。
14个回答

21
$search  = "#^((?#
    the scheme:
  )(?:https?://)(?#
    second level domains and beyond:
  )(?:[\S]+\.)+((?#
    top level domains:
  )MUSEUM|TRAVEL|AERO|ARPA|ASIA|EDU|GOV|MIL|MOBI|(?#
  )COOP|INFO|NAME|BIZ|CAT|COM|INT|JOBS|NET|ORG|PRO|TEL|(?#
  )A[CDEFGILMNOQRSTUWXZ]|B[ABDEFGHIJLMNORSTVWYZ]|(?#
  )C[ACDFGHIKLMNORUVXYZ]|D[EJKMOZ]|(?#
  )E[CEGHRSTU]|F[IJKMOR]|G[ABDEFGHILMNPQRSTUWY]|(?#
  )H[KMNRTU]|I[DELMNOQRST]|J[EMOP]|(?#
  )K[EGHIMNPRWYZ]|L[ABCIKRSTUVY]|M[ACDEFGHKLMNOPQRSTUVWXYZ]|(?#
  )N[ACEFGILOPRUZ]|OM|P[AEFGHKLMNRSTWY]|QA|R[EOSUW]|(?#
  )S[ABCDEGHIJKLMNORTUVYZ]|T[CDFGHJKLMNOPRTVWZ]|(?#
  )U[AGKMSYZ]|V[ACEGINU]|W[FS]|Y[ETU]|Z[AMW])(?#
    the path, can be there or not:
  )(/[a-z0-9\._/~%\-\+&\#\?!=\(\)@]*)?)$#i";

刚刚稍微整理了一下。这将匹配HTTP(s)地址,并且只有你从IANA正确复制了所有顶级域名的情况下,才能匹配那些标准化的域名(它不会匹配http://localhost),并且要声明http://

最后,如果存在路径部分,它将始终以/开头。

然而,我建议跟随Cerebrus:如果您对此不确定,请以更温和的方式学习正则表达式,并使用经过验证的模式来处理复杂的任务。

干杯,

顺便说一句:您的正则表达式还将匹配something.rsomething.h(在您的示例中|TO|和|TR|之间)。 我在我的版本中将它们省略掉了,因为我猜这是一个打字错误。

重新阅读问题:请更改

  )(?:https?://)(?#

为了

  )(?:https?://)?(?#

(多了一个 ?)以匹配没有方案的“URLs”。


1
但我不想强制在开头加上"http://",因为我希望它也能匹配"abc.com"。 - Alec Smart
我怀疑这个方法无法捕捉到所有的开放域名后缀,比如big.wong。 - Eddie
@Eddie 请考虑一下:答案来自于2009年,评论来自2011年。在自然语言中,您还需要检测IRI,这将非常接近无用的/\w+\.\w+/u。那么我们该怎么办呢?最后的办法是使用自然语言处理并尝试解析文本以获得意义的理解。 - Boldewyn
@Boldewyn,请问您是通过哪个工具或流程构建了"MUSEUM"…"Z[AMW]"这部分的呢?我猜想这不是手工完成的吧?这真的很令人印象深刻。 - James Cropcho
当我在2009年编制这个列表时,还没有像.google或.books这样的新式通用顶级域名,所以是的,我是手动编制的。这也意味着正则表达式现在已经过时了,因为它无法匹配任何较新的顶级域名。我建议采用实用的\.[a-z]+方法,而不是试图跟上新定义的顶级域名。关于最大长度:将+替换为{1,63}。这是“标签”部分。但是253个字符的总部分需要单独完成。 - Boldewyn
显示剩余4条评论

12

这并不完全符合提问者的要求,但这是一个更简单的正则表达式,不需要在IANA引入新TLD时进行更新。我认为对于大多数简单需求来说,这更加适用:

^(?:https?://)?(?:[\w]+\.)(?:\.?[\w]{2,})+$

没有TLD的列表,localhost不匹配,子域名数量必须大于等于2,每个子域名的长度必须大于等于2(例如:"a.a"不能匹配但"a.ab"可以匹配)。


所以这个不匹配URL的路径和查询参数部分? - lulalala
1
也无法匹配 URL 中的连字符。 - Styphon
1
你需要转义 https?:// 中的斜杠,但仍然太宽泛了。你可以在这里测试:http://www.regexr.com/ - ahmd0
似乎与子域名不匹配,例如https://consent.cookiebot.com。 - VilladsR
似乎与子域名不匹配,例如https://consent.cookiebot.com。 - undefined

8

这个问题很难找到答案。我发现的正则表达式太复杂了,而且除了正则表达式之外的任何东西都过于繁琐和难以实现。

最终得出:

/(\S+\.(com|net|org|edu|gov)(\/\S+)?)/

可以与 http://example.com, https://example.com, example.com, http://example.com/foo 一起使用。

说明:

  • 查找 .com 等
  • 匹配它之前的所有内容,直到空格
  • 匹配它之后的所有内容,直到空格

1
这也将匹配字符串,例如".com",但不是域的一部分,例如"http://example.zork/foo/.com/bar",并省略所有特定于国家/地区的顶级域(如.uk、.ca等)和其他域。 - TextGeek
1
+1 是让您选择要接受哪些域,尽管我会确保指出。在域名后添加单词边界(\b)可防止匹配该域名但继续扩展的命中,如 example.commerce 或 example.governance。/(\S+.(com|net|org|edu|gov)\b(/\S+)?)/ - Luigi

6
这将完整获取任何URL,包括?=和#/(如果存在):
/[A-Za-z]+:\/\/[A-Za-z0-9\-_]+\.[A-Za-z0-9\-_:%&;\?\#\/.=]+/g

也匹配 hap://foo.com/ :) - stelios
这会省略一些被允许的字符,如撇号、!、双引号和加号;只有在后面跟着2个十六进制数字时,%才应该被允许。更不用说国际化URI(IRI)/。 - TextGeek

1

使用单个正则表达式匹配URL字符串会使代码难以阅读。我建议使用parse_url将URL拆分为其组件(这不是一项微不足道的任务),并使用正则表达式检查每个部分。


1

将正则表达式的结尾更改为(/\S*)?)$应该可以解决您的问题。

解释一下这是在做什么 -

  • 它正在寻找/后面跟着一些字符(不是空格)
  • 此匹配是可选的,?表示0或1次
  • 最后应该跟随字符串的结尾(或将其更改为\b以匹配单词边界)。

1
我认为这是简单而高效的 /^(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$/

0

这就是它:

_^(?:(?:https?|ftp)://)(?:\S+(?::\S*)?@)?(?:(?!10(?:\.\d{1,3}){3})(?!127(?:\.\d{1,3}){3})(?!169\.254(?:\.\d{1,3}){2})(?!192\.168(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\x{00a1}-\x{ffff}0-9]+-?)*[a-z\x{00a1}-\x{ffff}0-9]+)(?:\.(?:[a-z\x{00a1}-\x{ffff}0-9]+-?)*[a-z\x{00a1}-\x{ffff}0-9]+)*(?:\.(?:[a-z\x{00a1}-\x{ffff}]{2,})))(?::\d{2,5})?(?:/[^\s]*)?$_iuS

0

正则表达式匹配所有网址(包括带有www或不带www,带有http或https或不带,包括所有2-6个字母的顶级域名[例如'ly','us'],端口,查询字符串和锚点['#'])。

虽然不是100%准确,但比我在网上看到的任何东西都要好。

它使用第一个答案中的顶级域名,结合我搜索到的其他技术。它将返回任何具有边界的有效网址,这就是\b发挥作用的地方。由于尾部的'/'也被\b触发,因此最后一个是匹配一个或多个'?'。

/\b((http(s?):\/\/)?([a-z0-9\-]+\.)+(MUSEUM|TRAVEL|AERO|ARPA|ASIA|EDU|GOV|MIL|MOBI|COOP|INFO|NAME|BIZ|CAT|COM|INT|JOBS|NET|ORG|PRO|TEL|A[CDEFGILMNOQRSTUWXZ]|B[ABDEFGHIJLMNORSTVWYZ]|C[ACDFGHIKLMNORUVXYZ]|D[EJKMOZ]|E[CEGHRSTU]|F[IJKMOR]|G[ABDEFGHILMNPQRSTUWY]|H[KMNRTU]|I[DELMNOQRST]|J[EMOP]|K[EGHIMNPRWYZ]|L[ABCIKRSTUVY]|M[ACDEFGHKLMNOPQRSTUVWXYZ]|N[ACEFGILOPRUZ]|OM|P[AEFGHKLMNRSTWY]|QA|R[EOSUW]|S[ABCDEGHIJKLMNORTUVYZ]|T[CDFGHJKLMNOPRTVWZ]|U[AGKMSYZ]|V[ACEGINU]|W[FS]|Y[ETU]|Z[AMW])(:[0-9]{1,5})?((\/([a-z0-9_\-\.~]*)*)?((\/)?\?[a-z0-9+_\-\.%=&]*)?)?(#[a-zA-Z0-9!$&'()*+.=-_~:@/?]*)?)/gi

正则表达式末尾的“/?”是什么意思?你是不是想说“/?”? - user354134
似乎无法针对以下内容正常工作:"http://s3.amazonaws.com/plivocloud/4c743546-7e1b-11e2-9060-002590662312.mp3" - user354134

0

$:美元符号表示字符串的结尾。
例如,\d*$ 将匹配以数字结尾的字符串。 因此,您需要添加 $!


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