如何检查字符串中的值是否为IP地址

38

当我这样做时

ip = request.env["REMOTE_ADDR"]

我已经获取了客户端的IP地址。但我该如何验证一个变量中的值是否真的是一个IP地址?

请帮忙解答,谢谢。如果这个问题有重复,请原谅我没有努力去寻找……

编辑:

那IPv6的IP地址怎么办?


2
下次最好花点功夫找现有的解决方案。这里有两个链接:https://dev59.com/UnVD5IYBdhLWcg3wDXF3 和 https://dev59.com/F07Sa4cB1Zd3GeqP2U6o - ankitjaininfo
13个回答

53
Ruby已经在标准库中提供了所需的正则表达式。 请查看resolv
require "resolv"

"192.168.1.1"   =~ Resolv::IPv4::Regex ? true : false #=> true
"192.168.1.500" =~ Resolv::IPv4::Regex ? true : false #=> false

"ff02::1"    =~ Resolv::IPv6::Regex ? true : false #=> true
"ff02::1::1" =~ Resolv::IPv6::Regex ? true : false #=> false

如果你喜欢简单直接的方式...
require "resolv"

!!("192.168.1.1"   =~ Resolv::IPv4::Regex) #=> true
!!("192.168.1.500" =~ Resolv::IPv4::Regex) #=> false

!!("ff02::1"    =~ Resolv::IPv6::Regex) #=> true
!!("ff02::1::1" =~ Resolv::IPv6::Regex) #=> false

玩得开心!
更新:
从下面的评论中,我喜欢用于检查IPv4或IPv6的非常简短的版本。
!!(ip_string =~ Resolv::AddressRegex)

非常优雅的Rails(也是下面的一个答案):
validates :ip,
          :format => {
            :with => Resolv::AddressRegex
          }

为了简化事情,((ip_string =~ Resolv::IPv4::Regex) || (ip_string =~ Resolv::IPv6::Regex)) ? true : false - gitb
3
!!((ip_string =~ Resolv::IPv4::Regex) || (ip_string =~ Resolv::IPv6::Regex)) 可以进一步简化。 - jesal
2
我更喜欢 !!(ip_string =~ Regexp.union([Resolv::IPv4::Regex, Resolv::IPv6::Regex])) - Sam
非常有帮助的答案。 - Jigar Bhatt
1
FYI Resolv::AddressRegex 存在(从 Ruby 1 开始),它包含了 IPv4 和 IPv6 的并集,因此你可以使用它而不是自己组合。代码 - salty

44

为什么不让一个库为你验证它?你不应该引入难以维护的复杂正则表达式。

% gem install ipaddress

那么,在你的应用程序中

require "ipaddress"

IPAddress.valid? "192.128.0.12"
#=> true

IPAddress.valid? "192.128.0.260"
#=> false

# Validate IPv6 addresses without additional work.
IPAddress.valid? "ff02::1"
#=> true

IPAddress.valid? "ff02::ff::1"
#=> false


IPAddress.valid_ipv4? "192.128.0.12"
#=> true

IPAddress.valid_ipv6? "192.128.0.12"
#=> false

您也可以使用Ruby内置的IPAddr类,但它并不适合验证。

当然,如果应用程序服务器或框架向您提供了IP地址,则无需进行验证。只需使用给定的信息,并优雅地处理任何异常即可。


15
require 'ipaddr'
!(IPAddr.new(str) rescue nil).nil?

我使用它进行快速检查,因为它使用了内置库。支持IPv4和IPv6。虽然不是非常严格,但例如它会认为'999.999.999.999'是有效的。如果您需要更高的精度,请参见获胜答案。


!!IPAddr.new(str) rescue false 这段代码更好。 - Tim Kretschmer
1
在当前库(Ruby 2.4.2)中,只有如果所有数字组都在允许范围内(IPv4的0到255)才正确验证地址。 IPAddr.new '999.999.999.999' => IPAddr :: InvalidAddressError:无效地址 - MatzFan

11

由于大多数答案都没有涉及IPV6验证,我遇到了类似的问题。我通过使用Ruby正则表达式库解决了它,如@wingfire所提到的。

但我还使用了Regexp Library来使用其union方法,如此处所述。

因此,我有了以下代码进行验证:

validates :ip, :format => { 
                  :with => Regexp.union(Resolv::IPv4::Regex, Resolv::IPv6::Regex)
                }

希望这能对某人有所帮助!


5

使用http://www.ruby-doc.org/stdlib-1.9.3/libdoc/ipaddr/rdoc/IPAddr.html可以为您执行验证。只需通过false捕获异常,您便知道它是否无效。

1.9.3p194 :002 > IPAddr.new('1.2.3.4')
 => #<IPAddr: IPv4:1.2.3.4/255.255.255.255> 
1.9.3p194 :003 > IPAddr.new('1.2.3.a')
ArgumentError: invalid address
  from /usr/local/rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/ipaddr.rb:496:in `rescue in initialize'
  from /usr/local/rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/ipaddr.rb:493:in `initialize'
  from (irb):3:in `new'
  from (irb):3
  from /usr/local/rvm/rubies/ruby-1.9.3-p194/bin/irb:16:in `<main>'

5
require 'ipaddr'

def is_ip?(ip)
  !!IPAddr.new(ip) rescue false
end

is_ip?("192.168.0.1")
=> true

is_ip?("www.google.com")
=> false

或者,如果您不介意扩展核心类:
require 'ipaddr'

class String
  def is_ip?
    !!IPAddr.new(self) rescue false
  end
end

"192.168.0.1".is_ip?
=> true

"192.168.0.512".is_ip?
=> false

4
所有以上答案都假设使用IPv4...在当今网络逐渐过渡到IPv6的时代,您必须考虑限制应用程序仅使用IPv4所带来的智慧。
如果问我:根本不要验证它。相反,只需将字符串原样传递给将使用IP地址的网络组件,并让它们进行验证。当它出错时捕获它们将抛出的异常,并使用该信息告诉用户发生了什么。不要重复造轮子,建立在他人工作的基础上。

顺便提一下,在 request.env['REMOTE_ADDR'] 中获取的内容始终是有效的 IP 地址,除非 Web 服务器出了问题!因此无需进行检查。 - ankitjaininfo
这是最好的建议。程序员们痴迷于语法验证,但不应该如此:将其传递给将使用它并验证它的程序。 - bortzmeyer

3

试试这个

使用 IPAddr

require 'ipaddr'
true if IPAddr.new(ip) rescue false

2

0

使用正则表达式进行验证:

\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}

2
999.999.999.999 不是一个有效的 IP 地址。 - Mischa
为了进行严格的检查,请使用此处指定的正则表达式:http://www.regular-expressions.info/regexbuddy/ipaccurate.html。 - ankitjaininfo
谢谢提供链接,很有趣。 - Mischa

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接