in reply to Re: Seeking an Enlightened Path (Parsing, Translating, Translocating)
in thread Seeking an Enlightened Path (Parsing, Translating, Translocating)

Unpack and then join. Very nice solution. I am getting my field definition before I would actually look at the file, so this is a very viable solution.

Is it possible to make this dynamically? In other words, would it be possible to define a string and feed that into unpack, then define another string and feed it into the second part of join? Also, if it is possible to make it dynamic in this way, would it hinder performance?

  • Comment on Re^2: Seeking an Enlightened Path (Parsing, Translating, Translocating)

Replies are listed 'Best First'.
Re^3: Seeking an Enlightened Path (Parsing, Translating, Translocating)
by NetWallah (Canon) on Mar 10, 2008 at 21:52 UTC
    Perl is a "dynamic language", and generally encourages late, lazy, and dynamic programming.(Sorry - could not find a better introductory platitude)

    Typically, built-in functions do not care (or are unaware) weather they are passed constants, or variables. The only exception I can think of is re-evaluating regular-expressions in a loop.

    So the advice is to go ahead and feed in constructed arguments. Benchmark it, if you have doubts.

         "As you get older three things happen. The first is your memory goes, and I can't remember the other two... " - Sir Norman Wisdom

Re^3: Seeking an Enlightened Path (Parsing, Translating, Translocating)
by ack (Deacon) on Mar 10, 2008 at 21:55 UTC

    Here is my stab at making it dynamic.

    #!/user/bin/perl use strict; use warnings; #----------- define field mappings --------------------- # hash to map from field i in input to field j in output # field i is the key to hash, field j is the value of hash my %from_to = ( 1 => 4, 2 => 2, 3 => 1, 4 => 3, ); # field length hash...key is the field number, value of hash # is the length in characters. Presumes the length of the # input and output fields are the same. my %field_len = ( 1 => 10, 2 => 4, 3 => 6, 4 => 6, ); #---------- setup decode string -------- my $decode_string = ""; foreach my $num (sort keys %from_to) {$decode_string .= 'A' . $field_len{$num} . ' '}; #-------------- process files ---------- my @input; my @output; foreach my $in_record (<DATA>) { chomp($in_record); print $in_record . " ---> "; @input =(unpack $decode_string,$in_record); foreach my $index (sort keys %from_to) {$output[($from_to{$index}-1)] = $input[($index-1)]}; my $out_record = join "",@output; print $out_record . "\n"; } exit(0); __END__ AAAAAAAAAA1111BBBBBB222222 BBBBBBBBBB2222CCCCCC333333 CCCCCCCCCC3333DDDDDD444444

    I used the two hashes to contain the mapping of the input field to the output field (%from_to) and the field lengths (%field_len). You, of course, could use whatever strategy you want.

    I also have prints in to see how things work.

    I had tried to make it more compact by trying to use a dynamic strategy for specifying the array slice as part of the join..decode line. But I couln't figure out (or remember) how to do that.

    ack Albuquerque, NM

      I figured out the compact way to make the single line join-unpack work while making it dynamic per nonotasher's request!

      The revised version of my original codes is in the following ReadMore:

      Which yields nanotasher's original desired result for:

      Input

      AAAAAAAAAA1111BBBBBB222222 BBBBBBBBBB2222CCCCCC333333 CCCCCCCCCC3333DDDDDD444444

      Output

      2222221111AAAAAAAAAABBBBBB 3333332222BBBBBBBBBBCCCCCC 4444443333CCCCCCCCCCDDDDDD

      This utilizes the wonderful single line join-unpack solution of BrowserUk but allows it to be dynamic.

      ack Albuquerque, NM
Re^3: Seeking an Enlightened Path (Parsing, Translating, Translocating)
by BrowserUk (Patriarch) on Mar 10, 2008 at 22:10 UTC
    In other words, would it be possible to define a string and feed that into unpack, then define another string and feed it into the second part of join?

    You'd have to explain that a little better, but someting like this might be close depending where/how you want to obtain those strings, The following would take comma separated arguments to construct the unpack template and field ordering:

    perl -e"BEGIN{$T=join'',map{qq[A$_ ]}split',',shift;@F=split',',shift}" -ple"$_ = join'',(unpack $T,$_)[@F]" "10,4,6,6" "2,1,0,3" infile >outfile

    But note I've had to split the "one-liner" over several lines for posting. Once they start getting this long, writing a proper script is more convenient if you are going to reuse it.


    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.