Problem with pack and Hh format specifiers

Hi,

I’m relatively new to Ruby so perhaps I’m missing something, but I can’t
get Array’s pack to work in the following situation:

irb(main):001:0> “%08b” % [“4”,“7”].pack (‘HXh’)[0]
“00000111”

I’m expecting to see “01000111”.

Note that unpack seems to work the way I would expect. (ASCII code for
’G’ is 01000111.)

irb(main):002:0> “G”.unpack (‘HXh’)
[“4”, “7”]

Can anyone shed any light on this?

I’m using Ruby 1.6.7 on a (mostly) Debian Woody linux system.

Thanks in advance,

Tony Sloane

Dept of Computing
Macquarie University

In article 1034037350.867.30.camel@awaji, Tony Sloane wrote:

Hi,

I’m relatively new to Ruby so perhaps I’m missing something, but I can’t
get Array’s pack to work in the following situation:

irb(main):001:0> “%08b” % [“4”,“7”].pack (‘HXh’)[0]
“00000111”

I’m expecting to see “01000111”.

What are you really trying to do?

There are some ugly ways to get [‘4’, ‘7’] into a string of 1’s and 0s:

irb(main):001:0> sprintf(‘%08b’, Integer(“0x” + [‘4’, ‘7’].join(‘’)))
“01000111”
irb(main):002:0> ‘%08b’ % [[“4”, “7”].join(“”)].pack(‘H*’)[0]
“01000111”
irb(main):003:0> [‘47’].pack(‘H*’).unpack(‘B*’)
[“01000111”]

Note that unpack seems to work the way I would expect. (ASCII code for
‘G’ is 01000111.)

irb(main):002:0> “G”.unpack (‘HXh’)
[“4”, “7”]

Depending on your context you may want to use H* as a template and split
the resulting string e.g.

irb(main):005:0> “G”.unpack(‘H*’)
[“47”]
irb(main):006:0> ‘banana’.unpack(‘H*’)
[“62616e616e61”]

I hope that I’m not off on some wild tangent, and that this is of some
use.

Regards,

Mike

···


mike@stok.co.uk | The “`Stok’ disclaimers” apply.
http://www.stok.co.uk/~mike/ | GPG PGP Key 1024D/059913DA
mike@exegenix.com | Fingerprint 0570 71CD 6790 7C28 3D60
http://www.exegenix.com/ | 75D2 9EC4 C1C0 0599 13DA

In article 1034037350.867.30.camel@awaji, Tony Sloane wrote:

I’m relatively new to Ruby so perhaps I’m missing something, but I can’t
get Array’s pack to work in the following situation:

irb(main):001:0> “%08b” % [“4”,“7”].pack (‘HXh’)[0]
“00000111”

I’m expecting to see “01000111”.

What are you really trying to do?

I’m trying to get a numeric byte comprised of 4 in the high nibble and 7
in the low nibble. The “%08b” etc is just there so we can see what I
get in an understandable format, not because I want a string.

If I use H and h separately I get what I expect.

irb(main):003:0> “%08b” % [“4”].pack (‘H’)[0]
“01000000”
irb(main):004:0> “%08b” % [“7”].pack (‘h’)[0]
“00000111”

It would seem that packing a low (high) nibble obliterates the high
(low) nibble as a side effect, so when I back up a byte to write the
second nibble I overwrite the first with zeros. Packing the nibbles in
the other order seems to confirms this.

irb(main):009:0> “%08b” % [“7”,“4”].pack (‘hXH’)[0]
“01000000”

Is this feature of pack deliberate? It would seem to make it impossible
to pack nibbles.

There are some ugly ways to get [‘4’, ‘7’] into a string of 1’s and 0s:

irb(main):001:0> sprintf(‘%08b’, Integer(“0x” + [‘4’, ‘7’].join(‘’)))
“01000111”
irb(main):002:0> ‘%08b’ % [[“4”, “7”].join(“”)].pack(‘H*’)[0]
“01000111”
irb(main):003:0> [‘47’].pack(‘H*’).unpack(‘B*’)
[“01000111”]

Yes, there are a number of uglier ways to do it and I’m using one at the
moment as a workaround. I just hoped that the simple pack method would
work since it seems like it should be just the inverse of the unpack.

Note that unpack seems to work the way I would expect. (ASCII code for
‘G’ is 01000111.)

irb(main):002:0> “G”.unpack (‘HXh’)
[“4”, “7”]

Depending on your context you may want to use H* as a template and split
the resulting string e.g.

irb(main):005:0> “G”.unpack(‘H*’)
[“47”]
irb(main):006:0> ‘banana’.unpack(‘H*’)
[“62616e616e61”]

For my application the unpack (‘HXh’) above works fine to pick the data
apart.

I hope that I’m not off on some wild tangent, and that this is of some
use.

Thanks for taking the time to reply.

Cheers,
Tony

···

On Wed, 2002-10-09 at 03:10, Mike Stok wrote: