http://qs1969.pair.com?node_id=667578

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

Hello, Could you check this ?

I have a file (excel csv file )with the following structure

a;3 b;2;3 c;5;4 d;6

Is there a way to add ";" at the end of the lines which have only two elements ? Thanks

Replies are listed 'Best First'.
Re: adding ";" to void elements
by Limbic~Region (Chancellor) on Feb 12, 2008 at 14:57 UTC
    steph_bow,
    The naive way to do this might look like:
    #!/usr/bin/perl use strict; use warnings; while (<DATA>) { chomp; my @col = split /;/; push @col, '' for @col .. 2; print join ';', @col; print "\n"; } __DATA__ a;3 b;2;3 c;5;4 d;6
    A less naive solution would use a module from CPAN such as Text::CSV or Text::xSV. To understand why that is a better approach, take a few minutes with Super Search.

    Update: As noted by tye in the CB, this solution was originally not tested. I added chomp and changed @col .. 3; to @col .. 2;

    Cheers - L~R

      You get a similar solution using a very useful idiom if you replace

      my @col = split /;/; push @col, '' for @col .. 2; print join ';', @col;
      with
      my $len = 3; print join ';', (split(/;/), ('') x $len)[0 .. $len-1];
      assuming that there are at most two semi-colons in the string. The focus here is the way to create the default trailing elements. This is quite useful when you create hashes, where it's imperative to not have any missing (or extra) elements. For instance:
      my %foo = map { (split /:/, $_, 2)[0, 1] } # Implicit "default" undef. qw/ foo:bar baz zip:zap:zoom / ; use Data::Dumper; print Dumper(\%foo); __END__ $VAR1 = { 'baz' => undef, 'foo' => 'bar', 'zip' => 'zap:zoom' };
      A naive
      my %foo = map { split /:/ } ...;
      would've been disastrous.

      lodin

Re: adding ";" to void elements
by johngg (Canon) on Feb 12, 2008 at 15:24 UTC
    This works for two, one or even zero elements.

    use strict; use warnings; print map { qq{@{ [ join q{;}, @{ $_ } == 3 ? ( @{ $_ } ) : ( @{ $_ }, ( q{} ) x ( 3 - @{ $_ } ) ) ] }\n} } map { chomp; [ split m{;} ] } <DATA>; __END__ a;3 b;2;3 c;5;4 d;6 f

    The output.

    a;3; b;2;3 c;5;4 d;6; ;; f;;

    I hope this is useful.

    Cheers,

    JohnGG

Re: adding ";" to void elements
by poolpi (Hermit) on Feb 12, 2008 at 15:11 UTC
    #!/usr/bin/perl use strict; use warnings; map { print if s/\A (\w;\d) (?!;\d) / $1; /xms } <DATA>; __DATA__ a;3 b;2;3 c;5;4 d;6
    Output : a;3; d;6;
    hth,

    Poolpi
      map { print ... }

      That's worth at least two fifteen-yard penalties right there! I'm sort of horrified and impressed.

        It's for error checking, of course
        any { !$_ } map { print ... } ... and die;
        ;)
Re: adding ";" to void elements
by jwkrahn (Abbot) on Feb 12, 2008 at 16:34 UTC
    $ echo "a;3 b;2;3 c;5;4 d;6" | perl -pe'y/;//==1&&s/$/;/' a;3; b;2;3 c;5;4 d;6;
      I went beyond the spec, and padded lines with no semi-colons too...
      perl -e 's^$^";"x(2-y-;--)^e' -p data
      ---
      my name's not Keith, and I'm not reasonable.