【问题标题】:Parsing a CSV file for a specific IP address解析特定 IP 地址的 CSV 文件
【发布时间】:2017-05-14 03:39:00
【问题描述】:

在 Ruby 中,如何解析 CSV 文件并相应地输出信息?例如:

require 'csv'

class CountryFilter

  class << self

    def find_specs_by_ip_address(ip)
      CSV.foreach('GeoIPCountry.csv') do |row|
        if row =~ Regexp.union(ip)
          data = row.split(',')
          return data[5]
        else
          return 'Unable to find country specifications'
        end
      end
    end

  end

end

puts CountryFilter.find_specs_by_ip_address('72.247.167.255')

CSV 文件:

...
"72.247.88.0","72.247.89.255","1224169472","1224169983","US","United States"
"72.247.90.0","72.247.103.255","1224169984","1224173567","NL","Netherlands"
"72.247.104.0","72.247.144.255","1224173568","1224184063","US","United States"
"72.247.145.0","72.247.145.255","1224184064","1224184319","NL","Netherlands"
"72.247.146.0","72.247.167.255","1224184320","1224189951","US","United States"
"72.247.168.0","72.247.179.255","1224189952","1224193023","NL","Netherlands"
"72.247.180.0","72.247.181.255","1224193024","1224193535","US","United States"
"72.247.182.0","72.247.182.255","1224193536","1224193791","NL","Netherlands"
"72.247.183.0","72.247.183.255","1224193792","1224194047","US","United States"
...

如何解析这个 CSV 文件中的 IP 地址并输出它的来源国家/地区?

【问题讨论】:

  • 我猜前两列实际上表示 IP 范围。

标签: ruby csv parsing


【解决方案1】:

注意事项

  • row 已经是一个包含多个单元格的 CSV 行,您不必拆分任何内容并定义 data
  • 在这两种情况下,您的方法都在第一行之后返回:IP 是否找到。
  • 在未找到 IP 时返回 nil 可能比返回字符串更好。

重构代码

require 'csv'
class CountryFilter
  class << self
    def find_specs_by_ip_address(ip)
      CSV.foreach('GeoIPCountry.csv') do |row|
        return row.last if row.first(2).include?(ip)
      end
    end
  end
end

CountryFilter.find_specs_by_ip_address('72.247.167.255')
#=> "United States
CountryFilter.find_specs_by_ip_address('1.2.3.4')
#=> nil

v2

感谢@Felix 提供有见地的 cmets。

此方法现在将 ip1 和 ip2 视为 IP 范围的边界,并检查 ip 是否在此范围内:

require 'csv'
require 'ipaddr'

module IPFilter
  def self.find_country_by_ip_address(ip)
    ip = IPAddr.new(ip).to_i
    CSV.foreach('GeoIPCountry.csv') do |_, _, ip1, ip2, _, country_name|
      return country_name if (ip1.to_i..ip2.to_i).cover?(ip)
    end
  end
end

p IPFilter.find_country_by_ip_address('72.247.167.123')
#=> "United States"
p IPFilter.find_country_by_ip_address('1.2.3.4')
#=> nil

Range#cover?

如果 obj 在范围的开始和结束之间,则返回 true。

【讨论】:

  • 啊,这就解释了!非常感谢
  • 有没有办法找到接近 IP 的匹配项?例如,假设我有 127.0.0.1,如果找不到找到最接近的匹配为 127.0.0.1 等。
  • 请写另一个问题,因为结构会与当前的不同
  • 当你在重构时,我会重命名为 IPFilter,让它仍然返回整行并使其成为一个模块。 :)
  • 我不知道Ruby允许_?这很酷,很高兴知道
【解决方案2】:

试试这个,

...
CSV.foreach('GeoIPCountry.csv') do |a, b, c, d, e, country|
  return country if a == ip || b == ip
end
...

这是如何工作的?

  • row 已经用逗​​号分隔
  • 您可以解压块参数中的行以避免幻数

注意,最好给a, b, c, d, e 起更有意义的名字。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-06-02
    • 2015-09-14
    • 2010-09-27
    • 1970-01-01
    • 2011-07-28
    • 1970-01-01
    • 2020-08-06
    • 2014-10-11
    相关资源
    最近更新 更多