【问题标题】:How to check if a URL is valid如何检查 URL 是否有效
【发布时间】:2010-12-20 19:36:29
【问题描述】:

如何检查字符串是否为有效 URL?

例如:

http://hello.it => yes
http:||bra.ziz, => no

如果这是一个有效的 URL,我如何检查它是否与图像文件相关?

【问题讨论】:

标签: ruby


【解决方案1】:

注意:

正如@CGuess 所指出的,这个问题存在一个错误,并且已经记录了 9 年多,现在验证不是这个正则表达式的目的(请参阅https://bugs.ruby-lang.org/issues/6520)。




使用随 Ruby 分发的 URI 模块:

require 'uri'

if url =~ URI::regexp
    # Correct URL
end

就像 Alexander Günther 在 cmets 中所说,它检查字符串是否包含 URL。

要检查字符串 是否 是 URL,请使用:

url =~ /\A#{URI::regexp}\z/

如果您只想检查网页 URL(httphttps),请使用:

url =~ /\A#{URI::regexp(['http', 'https'])}\z/

【讨论】:

  • 这似乎不起作用:'http://:5984/asdf' =~ URI::regexp'http::5984/asdf' =~ URI::regexp 都返回 0。我希望它们返回 nil,因为它们都不是有效的 URI。
  • 本地主机上不是 :5984 端口 5984 吗?
  • 它实际上检查变量是否包含有效的 url。它将接受“examplecom”作为有效 URL。因为它包含一个。但是,如果您希望整个内容都是 URL,这将无济于事。
  • gotqn:根据 RFC 1738,这不是一个有效的 URL。
  • 不要使用这个,太糟糕了"http:"通过了这个正则表达式。
【解决方案2】:

与上面的答案类似,我发现使用这个正则表达式更准确:

URI::DEFAULT_PARSER.regexp[:ABS_URI]

这将使带有空格的 URL 无效,而 URI.regexp 由于某种原因允许使用空格。

我最近发现了一个为不同的 URI rgexps 提供的快捷方式。您可以直接从URI::#{key} 访问任何URI::DEFAULT_PARSER.regexp.keys

例如,:ABS_URI 正则表达式可以从URI::ABS_URI 访问。

【讨论】:

  • 如果您打算在任何时候使用 URI.parse,这绝对是要走的路。 URI::regexp 匹配某些在以后使用 URI.parse 时会失败的 URL。感谢您的提示。
  • 遗憾的是,这仅适用于 Ruby 1.9,而不是 1.8。
  • 但是,这行得通:/^#{URI.regexp}$/。问题是URI.regexp 没有锚定。带有空格的字符串不会将空格作为 URI 的一部分进行验证,而是验证空格之前的所有内容。如果该片段看起来像一个有效的 URI,则匹配成功。
  • 将 avendt 的评论应用于您的提案:'http://:5984/asdf' =~ URI::DEFAULT_PARSER.regexp[:ABS_URI] 给出 0,而不是 nil; 'http::5984/asdf'=~ URI::DEFAULT_PARSER.regexp[:ABS_URI] 给出 0; 'http://:5984/asdf' =~ /^#{URI.regexp}$/ 给出 0; 'http::5984/asdf' =~ /^#{URI.regexp}$/ 也给出 0。上述正则表达式都不是完全正确的,但是它们只会在非常奇怪的情况下失败,在大多数情况下这并不是什么大问题。
  • 仅供参考,URI::DEFAULT_PARSER.regexp[:ABS_URI]/\A\s*#{URI::regexp}\s*\z/ 相同
【解决方案3】:

当前答案的问题是a URI is not an URL

URI 可以进一步分类为定位符、名称或两者。这 术语“统一资源定位器”(URL)指的是 URI 的子集 除了识别资源之外,还提供了一种方法 通过描述资源的主要访问机制来定位资源 (例如,它的网络“位置”)。

由于 URL 是 URI 的子集,很明显,专门为 URI 进行匹配将成功匹配不需要的值。例如URNs:

 "urn:isbn:0451450523" =~ URI::regexp
 => 0 

话虽如此,据我所知,Ruby 没有解析 URL 的默认方法,因此您很可能需要 gem 来执行此操作。如果您需要专门匹配 HTTP 或 HTTPS 格式的 URL,您可以执行以下操作:

uri = URI.parse(my_possible_url)
if uri.kind_of?(URI::HTTP) or uri.kind_of?(URI::HTTPS)
  # do your stuff
end

【讨论】:

  • uri.kind_of?(URI::HTTP) 似乎对于这两种情况(http 和 https)都足够了,至少在 ruby​​ 1.9.3 中是这样。
  • 仍然遇到@skalee 在 jonuts 的回答下描述的问题
  • 总结,URI.parse(string_to_be_checked).kind_of?(URI::HTTP) 做得很好。
  • 此外,我们数据库中一个非常常见的错误输入表明人们倾向于使用许多斜杠:http:///neopets.com,不幸的是这也是有效的。检查是否存在主机名可以解决此问题:uri = URI(str) ; %w[http https].include?(uri.scheme) && !uri.host.nil?
【解决方案4】:

我更喜欢Addressable gem。我发现它更智能地处理 URL。

require 'addressable/uri'

SCHEMES = %w(http https)

def valid_url?(url)
  parsed = Addressable::URI.parse(url) or return false
  SCHEMES.include?(parsed.scheme)
rescue Addressable::URI::InvalidURIError
  false
end

【讨论】:

  • 我刚刚给 Addressable::URI.parse() 提供了最奇怪的字符串,看看它拒绝了什么。它接受了疯狂的东西。但是它不接受的第一个字符串是“:-)”。嗯。
  • 这是怎么得到这么多赞成的? Addressable::URI.parse 不会返回无效输入的 nil。
  • @mvw 您必须更具体地了解什么是如此糟糕。 Another poster asked the owner of the repo about a number of 'strange' URLs,他一一详细讲解。他签字同意,说过于放纵比过于限制成本要低。 (顺便说一句:我声称对有效 URL 没有专业知识!)
  • irb(main):034:0> valid_url?('asd!$@.com') => true
【解决方案5】:

这是一个相当老的条目,但我想我会继续贡献:

String.class_eval do
    def is_valid_url?
        uri = URI.parse self
        uri.kind_of? URI::HTTP
    rescue URI::InvalidURIError
        false
    end
end

现在您可以执行以下操作:

if "http://www.omg.wtf".is_valid_url?
    p "huzzah!"
end

【讨论】:

  • 这比上述解决方案效果好多。它没有上面列出的警告,也不接受像 javascript:alert('spam') 这样的 uri。
  • 但它也匹配http:/,这可能不是你想要的。
【解决方案6】:

对我来说,我使用这个正则表达式:

/^(http|https):\/\/[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/.*)?$/ix

选项:

  • i - 不区分大小写
  • x - 忽略正则表达式中的空格

您可以设置此方法来检查 URL 验证:

def valid_url?(url)
  return false if url.include?("<script")
  url_regexp = /^(http|https):\/\/[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/.*)?$/ix
  url =~ url_regexp ? true : false
end

使用它:

valid_url?("http://stackoverflow.com/questions/1805761/check-if-url-is-valid-ruby")

使用错误的 URL 进行测试:

  • http://ruby3arabi - 结果无效
  • http://http://ruby3arabi.com - 结果无效
  • http:// - 结果无效
  • http://test.com\n&lt;script src=\"nasty.js\"&gt;(只需检查“

使用正确的 URL 进行测试:

  • http://ruby3arabi.com - 结果有效
  • http://www.ruby3arabi.com - 结果有效
  • https://www.ruby3arabi.com - 结果有效
  • https://www.ruby3arabi.com/article/1 - 结果有效
  • https://www.ruby3arabi.com/websites/58e212ff6d275e4bf9000000?locale=en - 结果有效

【讨论】:

  • 以下标记为有效:"http://test.com\n&lt;script src=\"nasty.js\"&gt;",并且任何使用683 TLDs 之一且长度超过 5 个字符或具有两个或多个连续连字符的域都标记为无效。允许使用 0-65535 范围之外的端口号。 FTP 和 IP 地址显然是不允许的,但值得注意。
  • 这里很容易成为快速 url 检查的最佳最适用的解决方案。谢谢
  • irb(main):051:0> valid_url?('127.0.0.1') => false
【解决方案7】:

一般来说,

/^#{URI::regexp}$/

会很好,但如果你只想匹配 httphttps,你可以将它们作为选项传递给方法:

/^#{URI::regexp(%w(http https))}$/

如果您想拒绝像 ftp:// 这样的协议,这往往会更好一些。

【讨论】:

    【解决方案8】:

    这有点旧,但这是我的做法。使用 Ruby 的 URI 模块来解析 URL。如果它可以被解析,那么它就是一个有效的 URL。 (但这并不意味着可以访问。)

    URI 支持多种方案,另外您可以自己添加自定义方案:

    irb> uri = URI.parse "http://hello.it" rescue nil
    => #<URI::HTTP:0x10755c50 URL:http://hello.it>
    
    irb> uri.instance_values
    => {"fragment"=>nil,
     "registry"=>nil,
     "scheme"=>"http",
     "query"=>nil,
     "port"=>80,
     "path"=>"",
     "host"=>"hello.it",
     "password"=>nil,
     "user"=>nil,
     "opaque"=>nil}
    
    irb> uri = URI.parse "http:||bra.ziz" rescue nil
    => nil
    
    
    irb> uri = URI.parse "ssh://hello.it:5888" rescue nil
    => #<URI::Generic:0x105fe938 URL:ssh://hello.it:5888>
    [26] pry(main)> uri.instance_values
    => {"fragment"=>nil,
     "registry"=>nil,
     "scheme"=>"ssh",
     "query"=>nil,
     "port"=>5888,
     "path"=>"",
     "host"=>"hello.it",
     "password"=>nil,
     "user"=>nil,
     "opaque"=>nil}
    

    有关 URI 模块的更多信息,请参阅 the documentation

    【讨论】:

    • 我在尝试修复段错误时遇到了这个问题。在 Ruby 2.5.5 中使用 URI.parse 实际上是造成这种情况的原因 - 如果您不介意一些奇怪的情况失败,我会切换到下面的 @jonuts 答案。出于我的目的,我不在乎,所以这是理想的。
    【解决方案9】:

    你也可以使用一个正则表达式,也许像http://www.geekzilla.co.uk/View2D3B0109-C1B2-4B4E-BFFD-E8088CBC85FD.htm这样的东西,假设这个正则表达式是正确的(我还没有完全检查它)下面将显示网址的有效性。

    url_regex = Regexp.new("((https?|ftp|file):((//)|(\\\\))+[\w\d:\#@%/;$()~_?\+-=\\\\.&]*)")
    
    urls = [
        "http://hello.it",
        "http:||bra.ziz"
    ]
    
    urls.each { |url|
        if url =~ url_regex then
            puts "%s is valid" % url
        else
            puts "%s not valid" % url
        end
    }
    

    上面的例子输出:

    http://hello.it is valid
    http:||bra.ziz not valid
    

    【讨论】:

    • mailto 方案呢?还是 telnet、gopher、nntp、rsync、ssh 或任何其他方案? URL 比 HTTP 和 FTP 稍微复杂一些。
    • 编写正则表达式来验证 URL 很困难。为什么要打扰?
    • @Rimian,你不得不费心,因为URI 所能做的实际上是坏了。请参阅上面众多赞成的答案下的 cmets。不确定珍妮的回答是否正确,但希望人们更加认真地考虑它。 TBH 我最终选择了url.start_with?("http://") || url.start_with?("https://"),因为我只需要 HTTP 并且用户应该负责使用正确的 URL。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-04-11
    • 2019-10-28
    • 1970-01-01
    • 2010-10-29
    • 1970-01-01
    • 1970-01-01
    • 2021-10-12
    相关资源
    最近更新 更多