Числа неотрицательны
Если числа неотрицательны, мы можем кодировать каждые 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