IP to integer (ip2int, int2ip)
When storing IP in a database, it’s much better to store them as integers rather than VARCHAR(15). Here’s a handy function to convert an IP string to integer and back.
# Converts an IP string to integer
def ip2int(ip)
return 0 unless ip =~ /d{1,3}.d{1,3}.d{1,3}.d{1,3}/
v = ip.split('.').collect { |i| i.to_i }
return (v[0] << 24) | (v[1] << 16) | (v[2] << 8 ) | (v[3]);
end
# Converts an integer to IP string... could be prettier
def int2ip(int)
tmp = int.to_i
parts = []
3.times do |i|
tmp = tmp / 256.0
parts << (256 * (tmp - tmp.to_i)).to_i
end
parts << tmp.to_i
parts.reverse.join('.')
end
9 comments.
Hi,
I just found your nice code. I start thinking about your comment a la “could be prettier”. Here is my little effort.
Instead of “… 3.times … end” I use this:
for i in 0..3
parts > (8 * i)).to_s
end
The idea behind this is to bild a bit-mask
(256 ** (i + 1) – 1)
The second step is a binary AND, to exempt the relevant digits
(tmp & …)
and at least a binary shift back to the original position.
>> (8 * i)
If you use the code with a (mysql)-database you have to think about using a UNSIGNED INT column. It costs me one hour to figure out what’s going wrong with large ip-addresses.
Greetings and thanks for your code.
PapaBaer
Shit, it filters HTML, one more trial:
parts << ((tmp & (256 ** (i + 1) – 1)) >> (8 * i)).to_s
Ð¤Ð¸Ð³Ð½Ñ Ð¾Ð´Ð½Ð°ÐºÐ¾ получаетÑÑ
>> ip = ‘192.168.79.45′
=> “192.168.79.45″
>> ip =~ /d{1,3}.d{1,3}.d{1,3}.d{1,3}/
=> nil
>> ip =~ /d{1,3}.d{1,3}.d{1,3}.d{1,3}/
=> nil
>> ‘234.4566′ =~ /d{1,3}.d{1,3}.d{1,3}.d{1,3}/
=> nil
>> return 0 unless ‘234.4566′ =~ /d{1,3}.d{1,3}.d{1,3}.d{1,3}/
LocalJumpError: unexpected return
from (irb):11
>> 0 unless ‘234.4566′ =~ /d{1,3}.d{1,3}.d{1,3}.d{1,3}/
=> 0
>> 0 unless ‘234.45.66.67′ =~ /d{1,3}.d{1,3}.d{1,3}.d{1,3}/
=> 0
>> ‘234.45.66.67′ =~ /d{1,3}.d{1,3}.d{1,3}.d{1,3}/
=> nil
>> ‘45.66.67′ =~ /d{1,3}.d{1,3}.d{1,3}.d{1,3}/
=> nil
Вот вроде решение подойдет
>> (’45.66.67′ =~ /[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}/).nil?
=> true
>> (’345.45.66.67′ =~ /[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}/).nil?
=> false
You can also use the ipaddr library to do the conversion for you.
require ‘ipaddr’
intip = IPAddr.new(”1.1.1.1″).to_i
=> 16843009
and the other way round:
ip = IPAddr.new(16843009, Socket::AF_INET).to_s
=> “1.1.1.1″
Probably best to use the iaddr lib but that takes all the fun out of it.
Here’s some interesting hacks..
For shortest data storage you could store as bytes and then get it back out with something like this.
def ip2bytes(ip)
v = ip.split(’.').collect { |i| i.to_i }
return [(v[0]
comment parser hacked up my prior post so.. maybe I’ll post a little at a time.
def ip2bytes(ip)
v = ip.split(’.').collect { |i| i.to_i }
return [(v[0]
Here’s some more..
def bytes2ip(ip_bytes)
ip_bytes.unpack(”C4″).join(”.”)
end
def int2ip(ip_bytes)
[ip_bytes].pack(”N”).unpack(”C4″).join(”.”)
end
Why not use IPAddr library?
Leave a Reply