Ruby: How to convert IP range to array of IP's
Use the Ruby standard library IPAddr
# I would suggest naming your function using underscore rather than camelcase
# because of Ruby naming conventions
#
require 'ipaddr'
def convert_ip_range(start_ip, end_ip)
start_ip = IPAddr.new(start_ip)
end_ip = IPAddr.new(end_ip)
# map to_s if you like, you can also call to_a,
# IPAddrs have some neat functions regarding IPs,
# be sure to check them out
#
(start_ip..end_ip).map(&:to_s)
end
How to convert IP range to a single CIDR using Ruby
Found it!
require 'netaddr'
startip = '250.154.64.0'
endip = '250.154.64.255'
ip_net_range = NetAddr.range(startip, endip, :Inclusive => true, :Objectify => true)
cidrs = NetAddr.merge(ip_net_range, :Objectify => true)
puts cidrs
output: 250.154.64.0/24
How to generate a list of IP addresses between two addresses with Ruby
Use IPAddr from the Ruby Stdlib.
IPAddr provides a set of methods to manipulate an IP address. Both
IPv4 and IPv6 are supported.
require 'ipaddr'
# I used a smaller number to limit the output
ip_range = IPAddr.new("192.168.1.3")..IPAddr.new("192.168.1.13")
ip_range.to_a
The output is an array of IPAddr instances.
=> [#<IPAddr: IPv4:192.168.1.3/255.255.255.255>, #<IPAddr: IPv4:192.168.1.4/255.255.255.255>, #<IPAddr: IPv4:192.168.1.5/255.255.255.255>, #<IPAddr: IPv4:192.168.1.6/255.255.255.255>, #<IPAddr: IPv4:192.168.1.7/255.255.255.255>, #<IPAddr: IPv4:192.168.1.8/255.255.255.255>, #<IPAddr: IPv4:192.168.1.9/255.255.255.255>, #<IPAddr: IPv4:192.168.1.10/255.255.255.255>, #<IPAddr: IPv4:192.168.1.11/255.255.255.255>, #<IPAddr: IPv4:192.168.1.12/255.255.255.255>, #<IPAddr: IPv4:192.168.1.13/255.255.255.255>]
A word of warning though. If you are taking user input make sure to catch the potential IPAddr::InvalidAddressError
that can occur.
begin
IPAddr.new(params[:from])..IPAddr.new(params[:to])
rescue IPAddr::InvalidAddressError
# @todo handle error
logger.info("Oh Noes!")
end
Convert a list of arrays into ip ranges
Convert the IP address to 32 bit integer (Assume you're dealing with IPv4 address according to your post), remove the duplicates, sort them, and do the merge. After that, convert the integers back to IP string:
require 'ipaddr'
def to_ranges(ips)
ips = ips.map{|ip| IPAddr.new(ip).to_i }.uniq.sort
prev = ips[0]
ips
.slice_before {|e|
prev2, prev = prev, e
prev2 + 1 != e
}
.map {|addrs| if addrs.length > 1 then [addrs[0], addrs[-1]] else addrs end }
.map {|addrs| addrs.map{|ip| IPAddr.new(ip, Socket::AF_INET)}.join("-") }
end
# some ip samples
ips = (0..255).map{|i| ["192.168.0.#{i}", "192.168.1.#{i}", "192.168.2.#{i}"] }.reduce(:+)
ips += ["192.168.3.0", "192.168.3.1"]
ips += ["192.168.3.5", "192.168.3.6"]
ips += ["192.168.5.1"]
ips += ["192.168.6.255", "192.168.7.0", "192.168.7.1"]
p to_ranges(ips)
# => ["192.168.0.0-192.168.3.1", "192.168.3.5-192.168.3.6", "192.168.5.1", "192.168.6.255-192.168.7.1"]
Reading IP addresses from file and storing them in an array should be relatively easy. 2 million IP addresses is a small set. You don't need to worry to much about the memory usage. (If it really matters, you may need to implement a algorithm to incrementally convert and merge the addresses)
BTW, I found the handy method Enumerable#slice_before when solving your problem.
How to manually convert an integer into an IP address in Ruby
An IP is just a 32-bit integer representing a 4-byte array:
[631271850].pack('N').unpack('CCCC').join('.')
=> "37.160.113.170"
Just for fun, another way to convert IP to int:
"37.160.113.170".split(".").map(&:to_i).pack('CCCC').unpack('N')[0]
=> 631271850
How to populate an array with IP address pattern
You're looking for map
Ranges are enumerables
so you can call map
on them. And it's also simpler and easier to understand:
(203..210).map { |i| "10.13.#{i}.3" }
Would give you:
#=> ["10.13.203.3", "10.13.204.3", "10.13.205.3", "10.13.206.3", "10.13.207.3", "10.13.208.3", "10.13.209.3", "10.13.210.3"]
Separate IP Range to Separate IPs
I have figured this out using Ruby code, and applied it after saving the Excel file as a tab-delimited TXT file.
def expand_lines(line)
id, inst, ip = line.split("\t")
ip_compontents = ip.split('.')
if ip_compontents[2] =~ /(\d+)-(\d+)/
$1.to_i.upto($2.to_i).map do |i|
new_ip = [*ip_compontents[0..1], i, ip_compontents[3]].join('.')
[id, inst, new_ip]
end
else
[[id, inst, ip]]
end
end
if $0 == __FILE__
ext = File.extname(ARGV[0])
base = File.basename(ARGV[0], ext)
dir = File.dirname(ARGV[0])
outfile = File.join(dir, "#{base}_expanded#{ext}")
expanded = IO.read(ARGV[0]).split("\n").map {|l| expand_lines(l.chomp)}.flatten(1)
File.open(outfile, 'w') do |f|
f.puts expanded.map {|l| l.join("\t")}
end
end
Creating IP address range in Ruby
require 'ipaddr'
puts IPAddr.new("123.123.0.0/16").to_range.to_a
If you absolutely have to use the ambiguous "IP defines range" data in the question,
require 'ipaddr'
STDIN.read.each_line do |line|
num_zeroes = line[/(\.0)*$/].length / 2
ip_range_string = "#{line.chomp}/#{32 - num_zeroes * 8}"
puts IPAddr.new(ip_range_string).to_range.to_a
end
Count IP addresses
If you need to convert an IP to a range, you'll need a function that converts an IPv4 value to an integer, then do math on those:
require 'ipaddr'
def ip(string)
IPAddr.new(string).to_i
end
def parse_ip(string)
string.split(/\s+\-\s+/).collect { |v| ip(v) }
end
def ip_range(string)
ips = parse_ip(string)
ips.last - ips.first + 1
end
ip_range("10.2.3.10 - 10.2.3.15")
# => 6
That should do it.
Related Topics
Error When Installing Libv8 3.11.8.3
Issues with Installing Ruby 2.0.0 on MACos Catalina
What Are Fast Xml Parsers for Ruby
Why Does 6.Times.Map Work in Ruby 1.8.7 But Not 1.8.6
Action Mailer Smtp Google Apps
What Does a Single Splat/Asterisk in a Ruby Argument List Mean
Ruby on Rails: Converting "Somewordhere" to "Some Word Here"
Why Does Ruby Release Memory Only Sometimes
How to Set Correct Ruby Version in Gem Environment
Ruby - Return Byte Array Containing Two's Complement Representation of Bignum/Fixnum
Getting Count of Elements by 'Created_At' by Day in a Given Month
Ruby Spreadsheet Row Background Color
Have Delayed_Job Log "Puts", SQL Queries and Jobs Status
Ruby 'Require' Call Fails on Custom Code
Accessing JSON Objects in Ruby