Beefy Boxes and Bandwidth Generously Provided by pair Networks
XP is just a number
 
PerlMonks  

pack / unpack woes

by agoth (Chaplain)
on Aug 24, 2000 at 15:16 UTC ( #29395=perlquestion: print w/replies, xml ) Need Help??

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

The code below works and churns out two strings (CSV) from a single input data array. However, its getting too close to being obfuscated especially with the lc(pack_format) in the middle.
Pointers and improvements requested

sub split_up { my $ary_ref = shift; my @d = @{ $ary_ref }; my $CUST_FMT = 'A A9 A3 A60 A10 A20 A40 A35 A35 A35 A35 A35 A10 A +3 A20 A20 A20 A50 A A A A A6 A6'; my $CHILD_FMT = 'A9 A20 A20 A20 A A A A6 A6 A6'; my ($a1, $a2, $a3, $a4, $a5) = ($d[4] =~ /.{35}?/g); my @cust_data = ('A', $d[0], 'WEB', '', $d[1], $d[2], $d[3], $a1, +$a2, $a3, $a4, $a5, $d[5], $d[6], $d[7], '', '', $d[8], '', $d [19], '', '', $d[18], ''); my @child_data = ($d[0], @d[9..17]); my $cust = join ',', (unpack lc($CUST_FMT), (pack $CUST_FMT, @cu +st_data)); my $child = join ',', (unpack lc($CHILD_FMT), (pack $CHILD_FMT, @c +hild_data)); return ($cust, $child); }

Replies are listed 'Best First'.
RE: pack / unpack woes
by nuance (Hermit) on Aug 24, 2000 at 17:39 UTC
    Well, I don't have a sample of your input data to play with, but it don't see the point of the pack/unpack thing. It seems to me that the following would do what you want. If it doesn't can you tell me what you're acheiving with the pack/unpack thing?
    sub split_up { my @d = @{ shift() }; my @a = ($d[4] =~ /.{35}?/g); for (0..4) { $a[$_] = '' unless exists $a[$_] }; my $cust = join ',', map lc ('A', $d[0], 'WEB', '', @d[1..3], @a, @d[5..7], '', '', $d[8], '', $d[19], '', '', $d[18], ''); my $child = join ',', map lc ($d[0], @d[9..17]); return ($cust, $child); }
    Update:
    Well as dave pointed out (and I suggested may be the case), I totally missed the point of the pack/unpack. I looked into sprintf, but I'm not convinced it's any better than your original (I haven't tested this).
    sub split_up { my @d = @{ shift() }; my @a = ($d[4] =~ /.{35}?/g); for (0..4) { $a[$_] = '' unless exists $a[$_] }; my $cu_fmt = ''; for (1, 9, 3, 60, 10, 20, 40, 35, 35, 35, 35, 35, 10, 3, 20, 20, 20, 50, 1, 1, 1, 1, 6, 6) { $cu_fmt .= "\%-${_}.${_}s," } my $cust = sprintf $cu_fmt, ('A', $d[0], 'WEB', '', @d[1..3], @a, @d[5..7], '', '', $d[8], '', $d[19], '', '', $d[18], ''); my $child_fmt = ''; for (9, 20, 20, 20, 20, 1, 1, 1, 6, 6, 6){ $child_fmt .= "\%-${_}.${_}s," } my $child = sprintf $child_fmt, ($d[0], @d[9..17]); return ($cust, $child); }

    Nuance

      I think you might be misundertanding what agoth is doing with the unpack lc($FMT}, pack $FMT, @data construction. Effectively the code is equivalent to this (simplifying the templates):

      $temp = pack 'A3 A4 A5', @data; @data = unpack 'a3 a4 a5', @data;

      Using 'A' in the pack template will pad each field with spaces to the width of the field as given in the template and using 'a' in the unpack template will leave those spaces untouched when the string is split again (using 'A' would strip the spaces)

      It might be easier to do something using sprintf and split.

      --
      <http://www.dave.org.uk>

      European Perl Conference - Sept 22/24 2000, ICA, London
      <http://www.yapc.org/Europe/>
      Davorg is right above!, but i should have explained my intentions with the data set.
      In @d, I want to pad items that are too short with spaces and crudely truncate items that are too long, and end up with a fixed width record.

      the lc(format) was the only way i could think of to turn all the A's to a's to preserve the spacing
      I just felt there must be a clearer way, looking into sprintf at the moment

        Something like this perhaps:

        my @list = (1, 2, 3); my $tmpl = '%-3s|%-4s|%-5s'; @list = split/\|/, sprintf $tmpl, @list; $" = '='; print "=@list=\n";

        ...although that won't truncate elements that are too big :(

        --
        <http://www.dave.org.uk>

        European Perl Conference - Sept 22/24 2000, ICA, London
        <http://www.yapc.org/Europe/>
      Well Nuances code below :

      for (1, 9, 3, 60, 10, 20, 40, 35, 35, 35, 35, 35, 10, 3, 20, 20, 20, 50, 1, 1, 1, 1, 6, 6) { $cu_fmt .= "\%-${_}.${_}s," } print "format = $cu_fmt \n";

      led me to this:

      @fmt = (1, 9, 3, 60, 10, 20, 40, 35, 35, 35, 35, 35, 10, 3, 20, 20, 20, 50, 1, 1, 1, 1, 6, 6); $cu_fmt = join ',', (map { "\%-${_}.${_}s" } @fmt ); print "format = $cu_fmt \n";

      but Im not sure either version is particularly easy to follow :-), cheers for the input though people.

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others making s'mores by the fire in the courtyard of the Monastery: (3)
As of 2022-05-22 23:19 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    Do you prefer to work remotely?



    Results (81 votes). Check out past polls.

    Notices?