数字是非负数
如果数字是非负数,我们可以将每个数字的每个 8 位编码为字符串的一部分,然后通过将每个字符转换为数字的 8 位来解码字符串。
def encode(n)
str = ''
until n.zero?
str << (n & 255).chr
n = n >> 8
end
str.reverse
end
def decode(str)
str.each_char.reduce(0) { |n,c| (n << 8) | c.ord }
end
这在 Integer 类中使用以下位操作方法:&、>>、<< 和 |。
def test(n)
encoded = encode(n)
puts "#{n} => #{encoded} => #{decode(encoded)}"
end
test 1 # 1 => ["\u0001"] => 1
test 63 # 63 => ["?"] => 63
test 64 # 64 => ["@"] => 64
test 255 # 255 => ["\xFF"] => 255
test 256 # 256 => ["\u0001", "\u0000"] => 256
test 123456 # 123456 => ["\x01", "\xE2", "@"] => 123456
例如,
n = 123456
n.to_s(2)
#=> "11110001001000000"
所以
n = 0b11110001001000000
#=> 123456
这个数字的字节可以这样可视化:
00000001 11100010 01000000
我们看到了
a = [0b00000001, 0b11100010, 0b01000000]
a.map(&:chr)
#=> ["\x01", "\xE2", "@"]
数字可以是负数
如果要编码的数字可以是负数,我们需要先将其转换为它们的绝对值,然后在编码字符串中添加一些信息,指示它们是非负数还是负数。这将需要至少一个额外的字节,因此我们可能包括一个用于非负数的 "+" 和一个用于负数的 "-"。
def encode(n)
sign = "+"
if n < 0
sign = "-"
n = -n
end
str = ''
until n.zero?
str << (n & 255).chr
n = n >> 8
end
(str << sign).reverse
end
def decode(str)
n = str[1..-1].each_char.reduce(0) { |n,c| (n << 8) | c.ord }
str[0] == '+' ? n : -n
end
test -255 # -255 => ["-", "\xFF"] => -255
test -256 # -256 => ["-", "\u0001", "\u0000"] => -256
test -123456 # -123456 => ["-", "\x01", "\xE2", "@"] => -123456
test 123456 # 123456 => ["+", "\x01", "\xE2", "@"] => 123456