Skeeve has asked for the wisdom of the Perl Monks concerning the following question:

Hi fellow monks!

I'm searching for a more elegant way to solve this problem. I have a string of 3 byte which contain fields of information packed in bits. These fields have variable length. The bit pattern is: AAABBCCD EEEEFFGH IIJJKLMM.

What I do now is similar to:

( $a, $b, $c, $d, $e, $f, $g, $h, $i, $j, $k, $l, $m )= map { unpack 'C', pack 'b*',$_ } unpack 'A3A2A2A1A4A2A1A1A2A2A1A1A2', unpack 'B*',$x;
So you see, I do:
  1. unpack my value to a string of '0' and '1's
  2. "split" it according to the lengths of the fields
  3. pack each individual substring to a string
  4. unpack it as an integer
Can you advise me of a better / more elegant way to achieve this?

Update: I just noticed: My code seemed to work, but didn't work as I expected... I'll update again when I found a working solution :-(

Update #2: Thanks to BrowserUK for finding a working solution!


s$$([},&%#}/&/]+}%&{})*;#$&&s&&$^X.($'^"%]=\&(|?*{%
+.+=%;.#_}\&"^"-+%*).}%:##%}={~=~:.")&e&&s""`$''`"e

Replies are listed 'Best First'.
Re: unpacking variable length bit fields
by BrowserUk (Patriarch) on Oct 24, 2006 at 12:00 UTC

    This is a little simpler.

    map oct( "0b$_" ), unpack 'A3A2A2A1A4A2A1A1A2A2A1A1A2', unpack 'B*', +$x;;

    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      Thanks! Not as elegant as I hoped but it has the big advantage: It works correct!

      s$$([},&%#}/&/]+}%&{})*;#$&&s&&$^X.($'^"%]=\&(|?*{%
      +.+=%;.#_}\&"^"-+%*).}%:##%}={~=~:.")&e&&s""`$''`"e

        I know what you mean. You want to be able to replace all the As with Bs and skip the first step, but of course each B starts a new byte. Maybe there could be something like unpack 'B{3,2,2,1}B{4,2,1,1}B{2,2,1,1,2}', $x?

        I've also had occassion to want to extract bit-ranges that cross byte boundaries and that gets real messy. Maybe an enhanced vec that allows non-powers-of-two sizes. That shouldn't be so hard to write.


        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.