增加了 ruby 版本的 内存查找
This commit is contained in:
parent
75bac23722
commit
168ea02ffc
|
|
@ -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
|
||||
|
|
@ -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}"
|
||||
Loading…
Reference in New Issue