in reply to Re^2: column counter and printf question
in thread column counter and printf question

A printf format is a perl string. In this case, it is constructed using perl's string operators. The dot ('.') is the concatenation operator. The 'x' is the repetition operator (Refer to Multiplicative Operators section of perlop). The specification '10.3f' is repeated @columns-3 times where @columns is the total number of columns. (The three comes from the fact that the first two columns are not printed and the third has it own format specification)
Bill
  • Comment on Re^3: column counter and printf question

Replies are listed 'Best First'.
Re^4: column counter and printf question
by fasoli (Beadle) on Oct 29, 2015 at 12:22 UTC

    Hi Bill,

    Thanks for the reply and the link, I get it now. Although one more question, should (@columns-3) maybe be ($columns-3)?

    Also, I'm a bit confused over the fact that the following pieces of code produce different output files. Can you take a look at the scripts and let me know where the problem is, as I can't understand it?

    #/bin/perl/ use strict; use warnings; open my $input, '<', './2kc29-out.txt' or die $!; open my $output, '>', 'test_thu1.txt' or die $!; while (my $line = <$input>) { chomp $line; $line =~ s/^\s+//; next if 1 .. $line =~ /\@TYPE xy/; #perlop range operators my @columns = split(/\s+/, $line); my $format = "%8.3f" . "%10.3f"x(@columns-3) . "\n"; printf $output $format, @columns[2..$#columns]; }
    and the second one:
    #/bin/perl/ use strict; use warnings; open my $input, '<', './2kc29-out.txt' or die $!; open my $output, '>', 'test_thu2.txt' or die $!; while (my $line = <$input>) { chomp $line; $line =~ s/^\s+//; next if 1 .. $line =~ /\@TYPE xy/; #perlop range operators my @columns = split /\s+/, $line; my $col1 = shift@columns; # column 1 (ignore) my $col2 = shift@columns; # column 2 (ignore) my $col3 = shift@columns; # column 3 (keep) my $result = printf $output ("%8.3f",$col3); # column 3 format # loop over remaining columns for my $c (@columns) { my $data = printf $output ("%10.3f",$c); $result .= " $data"; # append $result } printf $output "$result\n"; }

    The second script, prints a slightly bigger file (37.51MB over 31,28MB) because in the output it has printed dozens of random "1" numbers right after the last column. Why is this happening?

      should (@columns-3) maybe be ($columns-3)?

      No, there is no variable named $columns. In scalar context, @columns is the same as scalar @columns, which returns the number of elements in the @columns array. Since you want 3 less than the total number of array elements, @columns - 3 is correct.

      Can you take a look at the scripts and let me know where the problem is, as I can't understand it?

      The problem is with these lines in the second script:

      my $result = printf ... ... my $data = printf ...

      In both cases, printf should be sprintf. The latter returns the formatted string, which is what you want; the former returns “true” on success, hence the 1 numbers in the second output file. As the code now stands in the second script, the line my $data = printf $output ("%10.3f",$c); prints the formatted output to the output file, and sets $data to 1; then at the end of the for loop, all those 1s are printed to the file. You need something like this (untested):

      my $result = sprintf("%8.3f", $col3); # column 3 format # loop over remaining columns for my $c (@columns) { my $data = sprintf("%10.3f", $c); $result .= " $data"; # append $result } print $output "$result\n";

      Note that with this logic you don’t print to the output file until after the loop finishes.

      Hope that helps,

      Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

        Yes, that makes sense now. I actually counted the "1s" and they are 78 - as many as my columns, so now I see how printf also returned "true". Indeed, sprintf does the trick. Thanks for the explanation, I would have never thought that the problem was with printf.

        Now I know 2-3 different ways to count columns, the difference between printf and sprintf and also next if/unless :) Although I still haven't tried map, which I will do next. Thank you all!

      Although one more question, should (@columns-3) maybe be ($columns-3)?

      You're thinking of $#columns, which is the index of the last element in the array.

      @a = (1, 2, 3); $count = @a; printf "\$#a: %d versus \@a in scalar context: %d\n",$#a,$count;
      $#a is 2 versus @a in a scalar context is 3
      Dum Spiro Spero