diff --git a/binding/ruby/ip_2_region.rb b/binding/ruby/ip_2_region.rb new file mode 100644 index 0000000..4c730cf --- /dev/null +++ b/binding/ruby/ip_2_region.rb @@ -0,0 +1,76 @@ +class Ip2Region + INDEX_BLOCK_LENGTH = 12 + TOTAL_HEADER_LENGTH = 8192 + attr_accessor :f, :headerSip, :headerPtr, :headerLen, :indexSPtr, :indexLPtr, :indexCount, :dbBinStr + + def initialize(dbfile = "../../data/ip2region.db") + initDatabase(dbfile) + true + end + + def initDatabase(dbfile = "ip2region.db") + @dbBinStr = File.open(dbfile, 'rb').read + + @indexSPtr = getLong(@dbBinStr, 0) + @indexLPtr = getLong(@dbBinStr, 4) + @indexCount = ((indexLPtr - indexSPtr) / INDEX_BLOCK_LENGTH).to_i + 1 + # puts "#{@indexSPtr} #{@indexLPtr} #{@indexCount}" + end + + def memorySearch(ip) + ip = ip2long(ip) + + l, h, dataPtr = 0, indexCount , 0 + # print(l,h,dataPtr) + while l <= h + m = (l + h) >> 1 + p = m * INDEX_BLOCK_LENGTH + indexSPtr + # puts "m = #{m}, p = #{p}" + sip = getLong(@dbBinStr, p) + # puts "sip = #{sip}" + + if ip < sip + h = m - 1 + else + eip = getLong(@dbBinStr, p + 4) + if ip > eip + l = m + 1 + else + dataPtr = getLong(@dbBinStr, p + 8) + break + end + end + end + + if dataPtr == 0 + return nil + end + + returnData(dataPtr) + end + + def returnData(dataPtr) + dataLen = (dataPtr >> 24) & 0xFF + dataPtr = dataPtr & 0x00FFFFFF + data = @dbBinStr[dataPtr, dataLen] + # @dbBinStr.seek(dataPtr) + # data = @dbBinStr.read(dataLen) + + return { + :city_id => getLong(data, 0), + :region => data[4..-1].force_encoding("utf-8") + } + end + + def getLong(b, offset) + if (b[offset..offset+3] || []).length == 4 + # puts "unpack = #{b[offset..offset+3].unpack('I')}" + return b[offset..offset+3].unpack('I')[0].to_i + end + 0 + end + + def ip2long(ip) + ip.split('.').inject(0) {|s,x| s*256 + x.to_i} + end +end \ No newline at end of file diff --git a/binding/ruby/ip_2_region_test.rb b/binding/ruby/ip_2_region_test.rb new file mode 100644 index 0000000..4090140 --- /dev/null +++ b/binding/ruby/ip_2_region_test.rb @@ -0,0 +1,15 @@ +# 只实现了 memory 版本的, 其他的靠兄弟们实现了 + +require_relative 'ip_2_region' + +s = Ip2Region.new + +(1..235).each do |i| + ip = "#{i}.#{i}.#{i}.#{i}" + answer = s.memorySearch ip + puts "#{ip} , answer = #{answer}" +end + +ip = "27.10.228.9" +answer = s.memorySearch ip +puts "#{ip} , answer = #{answer}" \ No newline at end of file