【发布时间】:2010-12-20 19:36:29
【问题描述】:
如何检查字符串是否为有效 URL?
例如:
http://hello.it => yes
http:||bra.ziz, => no
如果这是一个有效的 URL,我如何检查它是否与图像文件相关?
【问题讨论】:
-
你提供的url好像是绝对url,相对于图片文件是什么意思
标签: ruby
如何检查字符串是否为有效 URL?
例如:
http://hello.it => yes
http:||bra.ziz, => no
如果这是一个有效的 URL,我如何检查它是否与图像文件相关?
【问题讨论】:
标签: ruby
正如@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(http 或 https),请使用:
url =~ /\A#{URI::regexp(['http', 'https'])}\z/
【讨论】:
'http://:5984/asdf' =~ URI::regexp 和 'http::5984/asdf' =~ URI::regexp 都返回 0。我希望它们返回 nil,因为它们都不是有效的 URI。
"http:"通过了这个正则表达式。
与上面的答案类似,我发现使用这个正则表达式更准确:
URI::DEFAULT_PARSER.regexp[:ABS_URI]
这将使带有空格的 URL 无效,而 URI.regexp 由于某种原因允许使用空格。
我最近发现了一个为不同的 URI rgexps 提供的快捷方式。您可以直接从URI::#{key} 访问任何URI::DEFAULT_PARSER.regexp.keys。
例如,:ABS_URI 正则表达式可以从URI::ABS_URI 访问。
【讨论】:
/^#{URI.regexp}$/。问题是URI.regexp 没有锚定。带有空格的字符串不会将空格作为 URI 的一部分进行验证,而是验证空格之前的所有内容。如果该片段看起来像一个有效的 URI,则匹配成功。
'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/ 相同
当前答案的问题是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 中是这样。
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?
我更喜欢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 不会返回无效输入的 nil。
这是一个相当老的条目,但我想我会继续贡献:
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
【讨论】:
http:/,这可能不是你想要的。
对我来说,我使用这个正则表达式:
/^(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<script src=\"nasty.js\">(只需检查“
使用正确的 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<script src=\"nasty.js\">",并且任何使用683 TLDs 之一且长度超过 5 个字符或具有两个或多个连续连字符的域都标记为无效。允许使用 0-65535 范围之外的端口号。 FTP 和 IP 地址显然是不允许的,但值得注意。
一般来说,
/^#{URI::regexp}$/
会很好,但如果你只想匹配 http 或 https,你可以将它们作为选项传递给方法:
/^#{URI::regexp(%w(http https))}$/
如果您想拒绝像 ftp:// 这样的协议,这往往会更好一些。
【讨论】:
这有点旧,但这是我的做法。使用 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。
【讨论】:
URI.parse 实际上是造成这种情况的原因 - 如果您不介意一些奇怪的情况失败,我会切换到下面的 @jonuts 答案。出于我的目的,我不在乎,所以这是理想的。
你也可以使用一个正则表达式,也许像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
【讨论】:
URI 所能做的实际上是坏了。请参阅上面众多赞成的答案下的 cmets。不确定珍妮的回答是否正确,但希望人们更加认真地考虑它。 TBH 我最终选择了url.start_with?("http://") || url.start_with?("https://"),因为我只需要 HTTP 并且用户应该负责使用正确的 URL。