如何检查URL是否有效


93

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

例如:

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

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


您提供的网址似乎是绝对网址,相对于图片文件,您的意思是什么
johannes

我发布了一个带有规格UriValidator
JJD 2013年

Answers:


177

使用URI随Ruby一起分发的模块:

require 'uri'

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

就像AlexanderGünther在评论中说的那样,它检查字符串是否包含 URL。

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

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

如果您只想检查Web URL(httphttps),请使用以下命令:

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

24
这似乎不起作用:'http://:5984/asdf' =~ URI::regexp并且'http::5984/asdf' =~ URI::regexp都返回0。我希望它们返回nil,因为它们都不是有效的URI。
2011年

4
本地主机上的:5984端口5984不是吗?
mxcl 2012年

3
它实际上检查变量是否包含有效的网址。它将接受“ example com”作为有效URL。因为它包含一个。但是,如果您希望整个内容都是URL,那将没有帮助。
亚历山大·冈瑟

2
gotqn:不过,根据RFC 1738,这不是有效的URL。
Mikael S

12
不要使用它,这太糟了,无法"http:"通过此正则表达式。
smathy

43

与上述答案类似,我发现使用此正则表达式会更加准确:

URI::DEFAULT_PARSER.regexp[:ABS_URI]

与URL相反,这将使URL无效 URI.regexp出于某种原因允许使用空格。

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

例如,:ABS_URI可以从访问regexp URI::ABS_URI


3
如果您打算在任何时候使用URI.parse,这绝对是正确的方法。URI :: regexp匹配某些URL,这些URL在以后使用URI.parse时将失败。谢谢你的提示。
markquezada 2011年

可悲的是,这仅在Ruby 1.9上可用,而在1.8上不可用。
史蒂夫·马德森

1
但是,这个工程:/^#{URI.regexp}$/。麻烦在于,这种URI.regexp锚不固定。带有空格的字符串不会将空格作为URI的一部分进行验证,而是导致空格的所有内容。如果该片段看起来像有效的URI,则匹配成功。
史蒂夫·马德森

3
将awendt的评论应用于您的提案:'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。以上正则表达式都不是完全正确的,但是它们仅在非常非常特殊的情况下会失败,这在大多数情况下并不重要。
skalee 2012年

1
仅供参考,URI::DEFAULT_PARSER.regexp[:ABS_URI]等同于/\A\s*#{URI::regexp}\s*\z/
aidan

34

当前答案的问题是URI不是URL

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

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

 "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

@Philip既有用又合适。非常感谢你!
fotanus 2013年

2
uri.kind_of?(URI::HTTP)至少在ruby 1.9.3中,这两种情况(http和https)似乎都足够。
Andrea Salicetti 2014年

仍然遭受@skalee在jnuts的回答下描述的问题
akostadinov

1
总结,URI.parse(string_to_be_checked).kind_of?(URI::HTTP)做得很好。

19

我更喜欢可寻址宝石。我发现它可以更智能地处理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

3
我只是用最奇怪的字符串输入了Addressable :: URI.parse()来查看它拒绝了什么。它接受了疯狂的东西。但是,它不接受的第一个字符串是“ :-)”。嗯
mvw

1
如何获得如此多的投票?Addressable::URI.parse输入无效时不返回nil。
垃圾收集者

11

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

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

2
这比上述解决方案好得多。它没有上面列出的警告,也不接受像javascript:alert('spam')这样的uri。
bchurchill 2013年

2
但它也匹配http:/,这可能不是您想要的。
Bo Jeanes

10

对我来说,我使用以下正则表达式:

/^(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)
  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")

使用错误的网址进行测试:

  • http://ruby3arabi -结果无效
  • http://http://ruby3arabi.com -结果无效
  • http:// -结果无效

使用正确的网址进行测试:

  • 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\">",并且使用长度超过5个字符或具有两个或多个连续连字符的683个TLD之一的任何域都标记为无效。允许使用0-65535范围之外的端口号。FTP和IP地址显然是不允许的,但值得注意的是。
–aidan

1
此处是用于快速URL检查的最合适的最佳解决方案。谢谢
somedirection

4

这有点旧了,但是这就是我的做法。使用Ruby的URI模块来解析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模块的更多信息,请参见文档


我遇到了试图修复段错误的问题。使用URI.parse实际上是在Ruby 2.5.5中导致此问题的原因-如果您不介意遇到一些奇怪的情况,我会在下面切换到@jonuts答案。对我来说,我不在乎,所以很理想。
el n00b

3

一般来说,

/^#{URI::regexp}$/

会很好地工作,但是如果您只想匹配httphttps,则可以将其作为选项传递给该方法:

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

如果您想拒绝类似的协议,则效果会更好一些ftp://


-2

您也可以使用正则表达式,例如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

5
mailto计划如何?还是telnet,gopher,nntp,rsync,ssh或其他任何方案?URL比HTTP和FTP稍微复杂一些。
亩太短了2010年

编写正则表达式来验证URL很困难。何必呢?
Rimian 2012年

@Rimian,您必须打扰,因为所有URI可以做的事实际上已被破坏。请参阅上面众多建议的答案下的评论。不确定珍妮的答案是否正确,但希望如此,人们希望它能更认真地考虑。我最终要做的url.start_with?("http://") || url.start_with?("https://")是TBH,因为我只需要HTTP,并且用户应该负责使用正确的URL。
akostadinov
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.