【问题标题】:Question about URL Validation with Regex [closed]关于使用正则表达式进行 URL 验证的问题 [关闭]
【发布时间】:2010-09-18 14:19:43
【问题描述】:

我有以下正则表达式可以很好地匹配 url:

((https?|ftp|gopher|telnet|file|notes|ms-help):((//)|(\\\\))+[\w\d:#@%/;$()~_?\+-=\\\.&]*)`

但是,它不处理没有前缀的 url,即。 stackoverflow.comwww.google.com 不匹配。任何人都知道我可以如何修改这个正则表达式而不关心是否有前缀?


编辑:我的问题是不是太含糊了?需要更多细节吗?


(((https?|ftp|gopher|telnet|file|notes|ms-help):((//)|(\\\\)))?[\w\d:#@%/;$()~_?\+-=\\\.&]*)

我加了一个()? Vinko Vrsalovic 建议的协议,但现在正则表达式几乎可以匹配任何字符串,只要它具有有效的 URL 字符。

我的实现是我有一个管理内容的数据库,它有一个包含纯文本、电话号码、URL 或电子邮件地址的字段。我正在寻找一种简单的方法来验证输入,以便我可以正确格式化它,即。为网址/电子邮件创建锚标记,并格式化电话号码,我如何在整个网站上格式化其他号码。有什么建议吗?

【问题讨论】:

  • 我必须补充一点,我并不是建议你真的这样做,只是告诉你这个正则表达式没有那个部分几乎没用
  • 在这种情况下有效是什么意思?那你要猜是哪个?

标签: regex url


【解决方案1】:

下面的正则表达式来自精彩的Mastering Regular Expressions 书。如果您对free spacing/comments mode不熟悉,建议您熟悉一下。

\b
# Match the leading part (proto://hostname, or just hostname)
(
    # ftp://, http://, or https:// leading part
    (ftp|https?)://[-\w]+(\.\w[-\w]*)+
  |
    # or, try to find a hostname with our more specific sub-expression
    (?i: [a-z0-9] (?:[-a-z0-9]*[a-z0-9])? \. )+ # sub domains
    # Now ending .com, etc. For these, require lowercase
    (?-i: com\b
        | edu\b
        | biz\b
        | gov\b
        | in(?:t|fo)\b # .int or .info
        | mil\b
        | net\b
        | org\b
        | name\b
        | coop\b
        | aero\b
        | museum\b
        | [a-z][a-z]\b # two-letter country codes
    )
)

# Allow an optional port number
( : \d+ )?

# The rest of the URL is optional, and begins with / . . . 
(
     /
     # The rest are heuristics for what seems to work well
     [^.!,?;"'<>()\[\]{}\s\x7F-\xFF]*
     (?:
        [.!,?]+  [^.!,?;"'<>()\[\]{}\s\x7F-\xFF]+
     )*
)?

为了简要解释这个正则表达式(完整的解释请看书)——URL 有一个或多个点分隔的部分,以有限的最终位列表结尾,或者两个字母的国家/地区代码 (.uk .fr ... )。此外,部件可以有任何字母数字字符或连字符“-”,但连字符不能是部件的第一个或最后一个字符。然后可能有一个端口号,然后是其余的。

要从网站上提取这个,去http://regex.info/listing.cgi?ed=3&p=207它来自第3版的第207页。

页面上写着“版权所有 © 2008 Jeffrey Friedl”,所以我不确定使用条件是什么,但我希望如果你拥有这本书,你可以使用它......我希望我没有违反规则把它放在这里。

【讨论】:

    【解决方案2】:

    如果您阅读 URL 规范 (http://www.isi.edu/in-notes/rfc1738.txt) 的第 5 部分,您会发现 URL 的语法至少是:

    scheme ':' schemepart
    

    其中scheme 是1 个或多个字符,schemepart 是0 个或多个字符。因此,如果没有冒号,就没有 URL。

    也就是说,/users/ 不在乎他们是否给了你一个 url,对他们来说它看起来像一个。所以这就是我要做的:

    在验证之前,如果其中没有冒号,请在前面加上 http://,然后通过您想要的任何验证器运行它。这会将任何合法的主机名(可能不包括域信息,毕竟)变成看起来像 URL 的东西。

    frob  ->  http://frob
    

    (几乎)主机部分的唯一规则是,如果它不包含点,则它不能以数字开头。现在,应该针对特定方案执行特定的验证,到目前为止给出的正则表达式都没有完成。但是,规范合规性可能不是您想要“验证”的内容。因此,对主机名部分的 dns 查询可能很有用,但除非您在与用户相同的上下文中使用相同的解析器,否则它不会在所有情况下都有效。

    【讨论】:

      【解决方案3】:

      您的正则表达式匹配从其中一个协议开始的所有内容,包括许多不可能存在的 URL 的内容,如果您放宽协议部分(使用 ? 使其可选),那么您将匹配几乎所有内容,包括空字符串。

      换句话说,它在匹配 URL 方面做得很好,因为它几乎可以匹配以 http://,https://,ftp:// 等开头的任何内容。好吧,它也匹配 ftp:\\ 和 ms-help://,但让我们忽略它。

      这可能有意义,具体取决于实际使用情况,因为将有效域列入白名单的其他正则表达式方法很快变得不可维护,但将协议部分设为可选则没有意义。

      一个例子(放宽协议部分就位):

      >>> r = re.compile('(((https?|ftp|gopher|telnet|file|notes|ms-help):((//)|(\\\\))+)?[\w\d:#@%/;$()~_?\+-=\\\.&]*)')
      >>> r.search('oompaloompa_is_not_an_ur%&%%l').groups()[0]
      'oompaloompa_is_not_an_ur%&%%l' #Matches!
      >>> r.search('oompaloompa_isdfjakojfsdi.sdnioknfsdjknfsdjk.fsdnjkfnsdjknfsdjk').groups()[0]
      'oompaloompa_isdfjakojfsdi.sdnioknfsdjknfsdjk.fsdnjkfnsdjknfsdjk' #Matches!
      >>>                             
      

      鉴于您的编辑,我建议您要么让用户选择他要添加的内容,添加一个枚举列,要么创建一个更简单的正则表达式,除了有效字符和一些常见域之外,它至少会检查一个点。

      第三种选择会非常慢并且仅在 URL 验证 非常非常重要 实际访问 URL 并对其执行 HEAD 请求时使用,如果您发现主机未找到或出现错误,您就知道它是无效的。对于电子邮件,您可以尝试查看 MX 主机是否存在并且端口 25 是否打开。如果两者都失败,它将是纯文本。 (我也不建议这样做)

      【讨论】:

        【解决方案4】:

        您可以将前缀部分括在括号中并匹配 0 或 1 个匹配项

        (((https?|ftp|gopher|telnet|file|notes|ms-help):((//)|(\\\\))+)?

        所以整个正则表达式会变成

        (((https?|ftp|gopher|telnet|file|notes|ms-help):((//)|(\\\\))+)?[\w\d:#@%/;$()~_?\+-=\\\.&amp;]*)

        问题在于它会或多或少地匹配任何单词。例如“测试”也将是一个匹配项。

        您打算在哪里使用该正则表达式?您是要验证主机名还是要在段落中查找主机名?

        【讨论】:

        • 我更新了我的帖子,并打算使用此代码。
        【解决方案5】:

        只需使用:

        .*
        

        即匹配一切。

        您要匹配的只是主机名,而不是 URL(技术上)。

        没有可用于明确识别主机名的结构。 也许您可以查找以“.com”结尾的内容,但您会错过任何 .co.uk、net、.org 等。

        编辑:

        换句话说:如果你取消了类似 URL 的东西以协议开头的要求,你将没有任何东西可以匹配。 取决于你在什么上使用正则表达式:

        1. 将所有内容都视为 URL
        2. 保留协议要求
        3. Hack 检查主机名的常见结尾(例如 .com .net .org)并接受您会遗漏一些。

        【讨论】:

        • 你是说用.*替换方括号的内容吗?
        • 不替换整个正则表达式。或者最好只是删除正则表达式并将所有内容视为 url。
        猜你喜欢
        • 2013-07-28
        • 1970-01-01
        • 2013-01-19
        • 1970-01-01
        • 2020-12-03
        • 2014-04-27
        • 2013-09-15
        • 2013-07-10
        • 2014-06-02
        相关资源
        最近更新 更多