【问题标题】:URL Validation - Accepts URLs without protocolsURL 验证 - 接受没有协议的 URL
【发布时间】:2011-03-24 16:52:59
【问题描述】:

我的应用程序中有一个基本的 URL 验证。现在我正在使用以下代码。

//validates whether the given value is 
//a valid URL
function validateUrl(value)
{
    var regexp = /(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/
    return regexp.test(value);
}

但现在它不接受没有协议的 URL。例如。如果我提供 www.google.com 它不接受它。如何修改 RegEx 以使其接受没有协议的 URL?

【问题讨论】:

  • 感谢您的所有回复。效果很好。
  • 您所有的正则表达式都接受@@##$$ 作为有效的 URL。有什么想法吗?
  • NLV,您没有指定您希望我们更正您的正则表达式,您只是询问如何更改它以接受任何协议。无论如何,请参阅下面的我的新答案,它提供了完整(和复杂)的 URL 验证正则表达式。

标签: javascript regex url


【解决方案1】:

这是一个用于匹配 URL 的大长正则表达式:

(?i)\b((?:(?:[a-z][\w-]+:)?(?:/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’]))

它的扩展版本(以帮助使其易于理解):

(?xi)
\b
(                           # Capture 1: entire matched URL
  (?:
    (?:[a-z][\w-]+:)?                # URL protocol and colon
    (?:
      /{1,3}                        # 1-3 slashes
      |                             #   or
      [a-z0-9%]                     # Single letter or digit or '%'
                                    # (Trying not to match e.g. "URI::Escape")
    )
    |                           #   or
    www\d{0,3}[.]               # "www.", "www1.", "www2." … "www999."
    |                           #   or
    [a-z0-9.\-]+[.][a-z]{2,4}/  # looks like domain name followed by a slash
  )
  (?:                           # One or more:
    [^\s()<>]+                      # Run of non-space, non-()<>
    |                               #   or
    \(([^\s()<>]+|(\([^\s()<>]+\)))*\)  # balanced parens, up to 2 levels
  )+
  (?:                           # End with:
    \(([^\s()<>]+|(\([^\s()<>]+\)))*\)  # balanced parens, up to 2 levels
    |                                   #   or
    [^\s`!()\[\]{};:'".,<>?«»“”‘’]        # not a space or one of these punct chars
  )
)

这些都来自this page,但稍作修改以使协议正确可选 - 您应该阅读该页面以帮助了解它在做什么,并且它还有一个仅匹配基于 Web 的 URL 的变体,您可能想要也来看看。

【讨论】:

  • 感谢您的努力。让我检查一下。
【解决方案2】:

将第一部分改为:

(?:(ftp|http|https):)?(?:\/\/)?

(?:...) 将在不使用捕获组的情况下对内容进行分组(因此实际协议保留在第一组中)。

注意protocol:// 部分是如何单独可选的 - 因为//www.google.com 是一个有效的(相对)URL。

【讨论】:

  • 不清楚你在说什么,这是一个很长的文件——你能参考你所指的具体部分吗?我在 Chrome 和 IE 中尝试过(例如)://google.com,但它不起作用,尽管 Firefox 看起来接受了它。
  • 架构集仅包含协议的名称(如“http”、“ftp”),但不包含冒号。因此,即使您的正则表达式也无法正确拆分所有组。但由于 NLV 只想为有效和常见(不仅有效)的 URL 提供验证正则表达式,因此不需要在斜杠周围使用组。
  • 内部组捕获httpftp 或其他值,外部组(冒号所在的位置)是非捕获的,并且是使整个事情可选的必要条件。同样,斜线周围的非捕获组需要使整个事情成为可选的(它可以使用\/{0,2},但这将允许/google.com,这可能是不需要的)。
【解决方案3】:

使用(...)? 使协议成为可选

/(((ftp|http|https):\/\/)|(\/\/))?(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/

【讨论】:

  • 这会将 ftp/http/https 移动到第 2 组,并且不接受 //server URL。
  • 查看我的编辑 - 现在它接受 protocol://// 或都不接受。
  • 您也可以使用(?:...) 从结果中排除组。
  • 这仍然使事情过于复杂,也不适用于http:google.com(因此,为什么在我的回答中我只使用了两个可选组)。包裹交替两侧的括号也是多余的,只会让事情变得更混乱。
【解决方案4】:

我不是正则表达式专家,但是用另一个括号括住协议并在末尾使用问号应该使它成为可选:

function validateUrl(value)
{
    var regexp = /((ftp|http|https):\/\/)?(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/
    return regexp.test(value);
} 

【讨论】:

  • 同样,如果这个正则表达式被用于捕获 URL 部分,它会创建不必要的组,并且它会错误地将 // 与排除有效 URL 的协议相结合。
  • 虽然 //google.com 有效,但它不是有效的 URL,我认为大多数人都不知道它会起作用,因此从验证中排除此类 URL 可能非常有用.不是因为它可能必须在每种形式中都有效。双斜杠只是介于两者之间,因为点是子域、域或 TLD 之间。
  • 双斜杠是路径的前缀,而冒号是协议的分隔符——它们是恰好一起出现的两个不同部分。 (这在 RFC 2396 的“3. URI 语法组件”中有详细说明)使用 //google.com 是一个有效的相对 Url(同样,请参见 RFC 2396 的附录“C.1 Normal Examples”)并且它确实发生在“野生”。
【解决方案5】:

将正则表达式更改为:

/((ftp|http|https):\/\/)?(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/

【讨论】:

  • 与 hsz 的回答一样,这会将 ftp/http/https 移动到第 2 组,并且不接受 //server URL。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-05-09
  • 2019-07-24
  • 1970-01-01
  • 1970-01-01
  • 2019-06-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多