On 6/4/05, Brian Candler <B.Candler / pobox.com> wrote: > I'm sure there ought to be a Ruby function to do this, but I've been > scratching my head whilst going through the Pickaxe book :-) > > I want to encode/decode a positive number to/from a variable-length > big-endian binary string. > > Originally the best I could come up with was: > > str = "\001\002\003" > val = 0 > str.each_byte { |b| val = (val << 8) | b } > p val > # => 66051 > > val = 1234 > str = "" > while (val > 0) > str = (val & 0xff).chr + str > val >>= 8 > end > p str > # => "\004\322" > > pack/unpack seem only to work for fixed lengths, e.g. 2 or 4 bytes. > > Is there a faster or simpler way of doing this in Ruby? > > Then I discovered I can go via hex: > > p "\001\002\003".unpack("H*")[0].hex > # => 66051 > > str = 1234.to_s(16) > str = "0#{str}" if str.length % 2 != 0 > val = [str].pack("H*") > p val > # => "\004\322" > > That's still pretty nasty. Any better offers? You're on the right track... It looks like you're just doing too much work. how about: [int.to_s(16)].pack('H*') to pack it, and: string.unpack('H*').first.to_i(16) to unpack? Also, if you aren't tied to this exact format, there's the BER-compressed integer option in #pack/#unpack, which handles variable-length integers in a nice way: [12345678901234567890].pack('w') ==>"\201\253\252\252\261\316\330\374\225R" [1].pack('w') ==>"\001" cheers, Mark