[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Fwd: Please Forward: Ruby Quiz Submission

James Gray

9/16/2007 3:25:00 PM



Begin forwarded message:

> From: "Luis Parravicini" <lparravi@gmail.com>
> Date: September 15, 2007 8:11:03 AM CDT
> To: submission@rubyquiz.com
> Subject: Please Forward: Ruby Quiz Submission
>
> I'm sending my solution to the ip-to-country Ruby Quiz. I've done two
> scripts, one to read IpToCountry.csv and create another file for quick
> access and another to search for the country the ip is in.
>
> The script to search which country a ip is in (ip.rb), uses a binary
> file created by the second script (pre-ip.rb) and performs a binary
> search on it.
> ----------------------------------------------------------------------
> ------------------------
> require 'readbytes'
>
> # reads the ip range for the record at position pos
> def read_ips(f, pos)
> f.pos = pos * 10
> buf = f.readbytes(8)
> [ buf[0, 4], buf[4, 8] ].map { |b| b.unpack('N')[0] }
> end
>
> # gets the country for the record at position pos
> def get_country(f, pos)
> f.pos = pos * 10 + 8
> f.readbytes(2)
> end
>
> # binary search of the ip (based on the binary search at
> # http://eigenclass.org/hiki.rb?simple+full+text+search+... )
> def binary_search(f, ip, from, to)
> while from < to
> middle = (from + to) / 2
> pivot = read_ips(f, middle)
>
> if ip < pivot[0]
> to = middle
> next
> elsif ip > pivot[1]
> from = middle+1
> next
> end
>
> if ip >= pivot[0] && ip <= pivot[1]
> return get_country(f, middle)
> else
> return nil
> end
> end
> end
>
> # converts the ip in a.b.c.d form to network order
> def to_network(ip)
> aux = ip.split('.').map { |x| x.to_i }
>
> aux[3] + (aux[2] << 8) + (aux[1] << 16) + (aux[0] << 24)
> end
>
>
> ip = ARGV[0]
> if ip.nil?
> puts "usage: #{__FILE__} ip_address"
> exit 1
> end
> ip = to_network(ip)
>
> File.open('ip_country', 'r') do |f|
> f.seek(0, IO::SEEK_END)
> records = f.tell / 10
>
> country = binary_search(f, ip, 0, records)
> country = 'not found' if country.nil?
> puts country
> end
> ----------------------------------------------------------------------
> ------------------------
>
> This is the script which needs to be run just once before ip.rb can be
> used. It reads IpToCountry.csv and creates a binary file of records of
> 10 bytes each. Each record has an ip range (from, to) and the country
> that range belongs to.
> ----------------------------------------------------------------------
> ------------------------
> File.open('ip_country', 'w') do |out|
> File.open('IpToCountry.csv', 'r') do |csv|
> while line = csv.gets do
> next unless line =~ /^"(\d+)","(\d+)"(?:,"[^"]+"){2},"([A-Z]+)"/
>
> out.write([$1.to_i].pack('N')) # from
> out.write([$2.to_i].pack('N')) # to
> out.write($3[0,2]) # country
> end
> end
> end
> ----------------------------------------------------------------------
> ------------------------
>
> And the times (on a 1.5Ghz Pentium M) are:
>
> $ time ruby ip.rb 190.16.89.91
> AR
>
> real 0m0.017s
> user 0m0.010s
> sys 0m0.000s
>
>
> The time it takes pre-ip.rb to create the file ip_country:
>
> $ time ruby pre-ip.rb
>
> real 0m2.810s
> user 0m2.590s
> sys 0m0.020s
>
>
> --
> Luis Parravicini
> http://ktulu.co...