Beefy Boxes and Bandwidth Generously Provided by pair Networks
Clear questions and runnable code
get the best and fastest answer
 
PerlMonks  

Word reverse

by amigero (Novice)
on Oct 13, 2010 at 23:29 UTC ( [id://865177]=perlquestion: print w/replies, xml ) Need Help??

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

Hello Monks, I cherish your knowledge, with thoughts of giving bread to the needy as I write this message.
I am dealing with binary data. In a hex editor ("fred") the lines would look like this.

45d2ff76893a0033
45d239a7dd200116

I have been extracting this data using the following command.
 unpack('v4',$rec)

However, I now need to word reverse this data.
so I need some code to make the above become:

ff7645d20033893a
39a745d20116dd20

I know I can do the following
for(my $jj=0;jj<4;jj++){
    $skipper = 50+jj*2;
    push @data, reverse unpack('x$skipper v2',$record)
}

But, is there a one-liner I can use? Efficiency is critical

Replies are listed 'Best First'.
Re: Word reverse
by BrowserUk (Patriarch) on Oct 14, 2010 at 00:43 UTC

    unpack knows how to deal efficiently with little/big-endian unsigned shorts without you having to do the byte-swapping yourself.

    In recent perl's there are actually two mechanisms:

    1. Little-endian: formats 'v' or 'S<'
    2. Big-endian: formats 'n' or 'S>'

    It's also worth noting that it is far more efficient to use a quantity specifier (number or * after the template character), than to step through the string picking out the individual words yourself.

    This demonstrates both template options and both quantity specifiers options. (either could be used with either):

    #! perl -slw use strict; my $raw = "\x45\xd2\xff\x76\x89\x3a\x00\x33"; my @leUShorts = unpack 'v4', $raw; print "@leUShorts"; my @leUShorts2 = unpack 'S<*', $raw; print "@leUShorts2"; my @beUShorts = unpack 'n4', $raw; print "@beUShorts"; my @beUShorts2 = unpack 'S>*', $raw; print "@beUShorts2"; __END__ C:\test>junk67 53829 30463 14985 13056 53829 30463 14985 13056 17874 65398 35130 51 17874 65398 35130 51

    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.
Re: Word reverse
by kennethk (Abbot) on Oct 13, 2010 at 23:46 UTC
    What did you try? What didn't work? We can be dramatically more helpful when you show us what you tried - see How do I post a question effectively?.

    Do you necessarily need to unpack the data before using it? Given that nature of what you require, the most natural fix to me would be using a regular expression. Specifically, I would replace every set of four letters with their transposition:

    #!/usr/bin/perl use strict; use warnings; my @lines = ('45d2ff76893a0033', '45d239a7dd200116'); for my $line (@lines) { $line =~ s/(.{4})(.{4})/$2$1/g; } print join "\n", @lines;

    Update:and since you've changed your spec, a one-liner:

    s/(.{4})(.{4})/$2$1/g for @lines;

    Note that the new code you've posted does not compile.

    Regarding your statement that "Efficiency is critical", that is a bad starting point - premature optimization is the root of all evil. Make it work first. If it is too slow, profile it and attack bottlenecks.

Re: Word reverse
by AnomalousMonk (Archbishop) on Oct 14, 2010 at 13:04 UTC

    As I understand the OP...

    The two byte binary data sequence 45d2 (specificaly qq{\x45\xd2}) would unpack with the 'v' specifier as the hex number 0xD245.

    >perl -wMstrict -le "my $bin = qq{\x45\xd2}; printf qq{0x%04X \n}, unpack 'v', $bin; " 0xD245

    With the first code example of the OP, the eight byte binary data sequence 45d2ff76893a0033 (or qq{\x45\xd2\xff\x76\x89\x3a\x00\x33}) would unpack as
    0xD245 0x76FF 0x3A89 0x3300.

    >perl -wMstrict -le "my $bin = qq{\x45\xd2\xff\x76\x89\x3a\x00\x33}; my @data = unpack 'v4', $bin; printf '0x%04X ', $_ for @data; " 0xD245 0x76FF 0x3A89 0x3300

    But as I understand it, amigero wants 0x76FF 0xD245 0x3300 0x3A89.

    >perl -wMstrict -le "my $bin = qq{\x45\xd2\xff\x76\x89\x3a\x00\x33}; my @data = map reverse(unpack 'v*'), unpack '(a4)*', $bin; printf '0x%04X ', $_ for @data; " 0x76FF 0xD245 0x3300 0x3A89

    It's a one-liner, but as far as 'efficiency' goes, the remarks of others are pertinent.

      As I understand the OP...

      I think you may well be right in your interpretation of what the OP has asked for.

      But the (only?) way the data could end up in that byte/word ordering, is if it is being stored as unsigned longs on a little-endian machine. In which case, it would be better to unpack it as such, and so avoid the slow, manual reordering:

      printf "%0x\n", $_ for unpack 'V2', "\x45\xd2\xff\x76\x89\x3a\x00\x33" +;; 76ffd245 33003a89 #or printf "%0x\n", $_ for unpack 'L<2', "\x45\xd2\xff\x76\x89\x3a\x00\x33 +";; 76ffd245 33003a89

      I'm always wary of these questions when they are couched in terms of "hex" and "binary", which means different things to different people. Often either term is misused to mean ascii-fied hex data.

      In this case, the impression left by the OPs code and question are, that he is a C programmer using perl and trying to do things "the C way", and is unaware of unpack.

      Finally, depending upon what 'mode' his hex editor is in, it could be that the byte ordering of the raw data is being 'messed' with for display.

      In much the same way as od appears to 'mess' with the ordering, depending upon how you ask it to interpret the data:

      c:\test>od -t xC src.bin 0000000 45 d2 ff 76 89 3a 00 33 0000010 c:\test>od -t x2 src.bin 0000000 d245 76ff 3a89 3300 0000010 c:\test>od -t x4 src.bin 0000000 76ffd245 33003a89 0000010

      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.
Re: Word reverse
by ssandv (Hermit) on Oct 14, 2010 at 00:02 UTC
    A one liner is not necessarily more efficient. If you really care about efficiency, use hand-coded byte swaps in assembly code.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://865177]
Approved by kennethk
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others making s'mores by the fire in the courtyard of the Monastery: (2)
As of 2024-04-26 01:05 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found