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

Wise monks, I ask your help for my unpack/pack ignorance. I need to present data in the same format as a Windows registry file (.reg, ascii not unicode)
Using the perl debugger, the hex data read from the registry looks like this:
DB<2> x $value 0 "\cA\cB\cC\cD\cE\cF\cG\cH\cI\cJ\cK\cL\cM\cN\cO\cZ\cP\cQ\cR\cS\cT\cU +\cV\cW\cX\cY\cZ\e\c\\c]\c^\c_ !\"#\$%&'()*+,-./0123456789:;<=>?\@ABCD +EFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
and after doing ( $value ) = unpack("H*", $value); it looks like this:
DB<3> x $value 0 '0102030405060708090a0b0c0d0e0f1a101112131415161718191a1b1c1d1e1f20 +2122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f4041424 +34445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f'

What I need is comma-separated two-digit numbers, like this:

01,02,03,04,05,06,07,08,09,0a,0b,0c,0d,0e,0f,1a,10,11,12,13,14,15,16,1 +7,18,19,1a,1b,1c,1d,1e,1f,20,21,22,23,24,25,26,27,28,29,2a,2b,2c,2d,2 +e,2f,30,31,32,33,34,35,36,37,38,39,3a,3b,3c,3d,3e,3f,40,41,42,43,44,4 +5,46,47,48,49,4a,4b,4c,4d,4e,4f,50,51,52,53,54,55,56,57,58,59,5a,5b,5 +c,5d,5e,5f
And I also need to be able to go in the opposite direction, from the comma-delimited numbers to hex data. How is this done? I'd really appreciate a code fragment rather than pointers to docs, as my mind seems unable to grasp this particular issue at present! Grateful thanks in hope.

Replies are listed 'Best First'.
Re: unpack and pack
by ikegami (Patriarch) on Apr 27, 2005 at 22:35 UTC
    $newvalue = join(',', (unpack('H*', $value) =~ /(..)/g))

    or

    ($newvalue = $value) =~ s/(.)/sprintf('%02x,', ord($1))/ge; chop($newvalue);

    or

    $newvalue = join(',', map { unpack('H*', $_) } split(//, $value));

    ...

Re: unpack and pack
by jmcnamara (Monsignor) on Apr 27, 2005 at 23:46 UTC

    Here is one way to do it:
    $str = join ',', map {sprintf "%02x", $_} unpack 'C*', $value; # And back $str =~ s/,//g; $value = pack "H*", $str;

    --
    John.

      Ikegami and John -- very many thanks to you both! Alan
      actually, still many thanks for the attempts, but Ikegami's and John's suggested solutions are giving ASCII versions. That is, instead of giving

      01,02,03,...

      they give

      30,31,30,32,30,33,...

Re: unpack and pack
by Roy Johnson (Monsignor) on Apr 28, 2005 at 18:47 UTC
    my $value = "\cA\cB\cC\cD\cE\cF\cG\cH\cI\cJ\cK\cL\cM\cN\cO\cZ\cP\cQ\cR +\cS\cT"; $value =~ s/(.)/sprintf "%02x,", ord($1)/sge; chop $value; print $value, "\n";
    or to create a new string instead of modifying the existing one:
    my $value = "\cA\cB\cC\cD\cE\cF\cG\cH\cI\cJ\cK\cL\cM\cN\cO\cZ\cP\cQ\cR +\cS\cT"; print join(',', map {sprintf "%02x", ord} split(//, $value)), "\n";

    Caution: Contents may have been coded under pressure.
      thanks!

      the ASCII interpretation must be caused by my code preceding the unpack, as this solution also gives the same 30,31,30,32 string using data my app has read from the registry, though it (and most likely ikegami's and John's solutions too) shows the correct 01,02,03 string from $value="\cA\cB..."

      Obviously it's time i understood more of what I'm doing!

Re: unpack and pack
by anadem (Scribe) on Apr 29, 2005 at 16:43 UTC
    just to repeat my thanks for all the solutions, and confirm that my stupidity extended beyond ignorance -- all the solutions are great, and my coding sucked. Thanks again!