Advertisement
Narzew

Huffman Encode/Decode Method (not mine)

Mar 31st, 2013
175
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Ruby 2.26 KB | None | 0 0
  1. # THIS IS NOT MINE METHOD. I FOUND IT AROUND THE INTERNET.
  2. class Huffman
  3.   def self.encode(string)
  4.     bytestream          = string.scan(/./m)
  5.     tree                = bytestream.uniq.collect{|c1| [c1, string.scan(c1).length]}
  6.     while tree.length > 1
  7.       a, b, *tree       = tree.sort_by{|_, count| count}        # Not deterministic.
  8.       tree << [[a[0], b[0]], a[1]+b[1]]
  9.     end
  10.     tree                = tree.shift.shift      unless tree.empty?
  11.     path_to_char =
  12.     lambda do |c, t|
  13.       res = "0"+path_to_char.call(c, t[0])      if [t[0]].flatten.include?(c)
  14.       res = "1"+path_to_char.call(c, t[1])      if [t[1]].flatten.include?(c)
  15.       res || ""
  16.     end
  17.     int8_to_bits        = lambda{|i| [i].pack("C").unpack("B*").shift}
  18.     byte_to_bits        = lambda{|c| c.unpack("B*").shift}
  19.     table               = bytestream.uniq.inject({}){|h, c| h[c] = path_to_char.call(c, tree) ; h}
  20.     len_table           = int8_to_bits[table.length]
  21.     ser_table           = table.collect{|c, bs| [int8_to_bits[bs.length], bs, byte_to_bits[c]]}.flatten.join("")
  22.     bitstring           = bytestream.collect{|c| table[c]}.join("")
  23.     message             = len_table + ser_table + bitstring
  24.     padding             = int8_to_bits[message.length%8 == 0 ? 0 : 8-message.length%8]
  25.     [padding + message].pack("B*")
  26.   end
  27.   def self.decode(string)
  28.     bitstring           = string.unpack("B*").shift
  29.     bits_to_int8        = lambda{|b| [b].pack("B*").unpack("C").shift}
  30.     bits_to_byte        = lambda{|b| [b].pack("B*")}
  31.     read_bits           = lambda{|n| x, bitstring = bitstring[0...n], bitstring[n..-1] ; x}     # Desctructive!
  32.     read_int8           = lambda{bits_to_int8[read_bits.call(8)]}                               # Desctructive!
  33.     read_byte           = lambda{bits_to_byte[read_bits.call(8)]}                               # Desctructive!
  34.     padding             = read_int8.call
  35.     bitstring           = bitstring[0...-padding]       if padding > 0
  36.     len_table           = read_int8.call
  37.     len_table           = 256   if len_table == 0
  38.     table               = (0...len_table).inject({}){|h, n| h[read_bits.call(read_int8.call)] = read_byte.call ; h}
  39.     bitstring.scan(/#{table.keys.join("|")}/).collect{|bits| table[bits]}.join("")
  40.   end
  41. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement