http://www.perlmonks.org?node_id=982869

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

I am a bit confused about how an unpack template works. For example:

#!/usr/bin/env perl use Modern::Perl; use Data::UUID; my $ug = Data::UUID->new; my $uuid = $ug->create_bin(); say unpack('H*', $uuid); # 767adecd8ed2e11191f4b1907aa0b7e4 my ($uu1, $uu2) = unpack('C4 C*', $uuid); say unpack('H*', $uu1); # Got 313138 Expected:767adecd say unpack('H*', $uu2); # Got 313232 Expected:8ed2e11191f4b1907aa0b7e4

I expected that 'C4 C*' would extract the first four bytes into $uu1 and C* would extract the rest into $uu2. Obviously I am not getting something here. Would appreciate an explanation

Thank you

Replies are listed 'Best First'.
Re: How do unpack templates work
by BrowserUk (Patriarch) on Jul 20, 2012 at 18:47 UTC

    Try:

    my( $bit1, $bit2 ) = unpack 'a4 a*', $uuid;

    But, regarding your "more efficient than substr" remarks. For the sake of a single operation like this, you won't notice the difference; even if there actually is any.


    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.

    The start of some sanity?

      Yes - that works! Thanks.

      I agree that the efficiency/speed argument is not particularly compelling in this case. But a single unpack (when written correctly ;) ) is way more elegant that a bunch of substr calls

      Will wait for a later day to better understand why 'C' does not work

        Will wait for a later day to better understand why 'C' does not work

        Don't wait. Try a few simple tests:

        print unpack 'H*', $uuid;; 767adecd8ed2e11191f4b1907aa0b7e4 print unpack 'a4', $uuid;; vzÌ═ print unpack 'C4', $uuid;; 118 122 222 205

        Look up what the 'C' template does. (Hint: see also ord ).


        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.

        The start of some sanity?

Re: How do unpack templates work
by daxim (Curate) on Jul 20, 2012 at 17:39 UTC
    The C template does not help you here. You're probably making a wrong assumption about it. Just stay with H if you want to make hex digits out of octets.

    my $uuid = "vz\336\315\216\322\341\21\221\364\261\220z\240\267\344"; # hex 767adecd8ed2e11191f4b1907aa0b7e4 my ($uu1, $uu2) = unpack('H8 H*', $uuid); say $uu1; # 767adecd say $uu2; # 8ed2e11191f4b1907aa0b7e4
      Thanks. I do not want hex digits - I just want to split the binary string into two parts. I was using
      substr
      until I read that unpack is faster and more efficient.

        Or you could use a regular expression:

        my ( $uu1, $uu2 ) = $uuid =~ /(\C{4})(\C+)/;
Re: How do unpack templates work
by flexvault (Monsignor) on Jul 21, 2012 at 07:16 UTC

    unlinker,

      "...I just want to split the binary string into two parts. I was using 'substr' until I read that unpack is faster and more efficient."

    First off, I luv 'pack/unpack', but it may not always be the most efficient. There are several way to determine performance, but an excellent tool to use is 'NYTprof'. I had a Perl script that I couldn't improve the performance no matter what I did. I profiled it and found that my problem was calling 'pack/unpack' too often. On a run of 50,000 records, the script was calling 'pack/unpack' over 5,000,000 times. The 'pack/unpack' was in a tight loop, working on 32 byte substrings of a 4K string.

    What came to the rescue was 'substr'. Using the 4 parameter as

    my $val = substr( $data, 0, 32, "" ); # $data already defin +ed
    In this situation, 'substr' just moves the pointer to the new beginning of the string, and was more efficient. I then used the 3 parameter non-destructive 'substr' to see it this was the substring I wanted, and then call 'pack/unpack'. Immediately, I saw a 300% improvement in performance and 'pack/unpack' was now called about 150,000 times.

    Perl has lots of powerful tools!

    Good Luck!

    "Well done is better than well said." - Benjamin Franklin