为了后代,这是我在发现 Paul Rubel 与“经典方法”的链接之前最终想出的方法。它很笨拙并且基于字符串操作,所以我可能会放弃它,但它确实有效,所以有一天有人可能会因为其他原因发现它很有趣:
# Returns an integer from the given little-endian binary string.
# @param [String] str
# @return [Fixnum]
def self.bson_to_int(str)
bits = str.reverse.unpack('B*').first # Get the 0s and 1s
if bits[0] == '0' # We're a positive number; life is easy
bits.to_i(2)
else # Get the twos complement
comp, flip = "", false
bits.reverse.each_char do |bit|
comp << (flip ? bit.tr('10','01') : bit)
flip = true if !flip && bit == '1'
end
("-" + comp.reverse).to_i(2)
end
end
更新:这是更简单的重构,使用 Ken Bloom 答案的广义任意长度形式:
# Returns an integer from the given arbitrary length little-endian binary string.
# @param [String] str
# @return [Fixnum]
def self.bson_to_int(str)
arr, bits, num = str.unpack('V*'), 0, 0
arr.each do |int|
num += int << bits
bits += 32
end
num >= 2**(bits-1) ? num - 2**bits : num # Convert from unsigned to signed
end