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

Hi, I thought this would be easy, but I can't seem to get it right. I want to use the printf command to print variables to specific column locations in a line. Here's an example:

printf MERGE (" %-s %s \(%2.4f %2.4f\)\n","$var1","$var2","$var3","$var4")

...and have, say, $var1 -> $var4 printed at col number 1, 20, 180, and 200, respectively. Should I just used \s deliminators? If so, how? I don't want to use the write command because the format would be difficult to keep tidy from one line to the next (there are hundreds of variables.)

Help!

Replies are listed 'Best First'.
Re: Formatting an output with printf
by kabel (Chaplain) on May 27, 2003 at 04:39 UTC
    you can specify the width of a "column":
    Z:\>perl use strict; printf STDOUT "[%-20s] [%20s]\n", 1000 .. 1001; ^D [1000 ] [ 1001] Z:\>
    HTH - be sure to check out this article by merlyn.
      If you want to be strict about your columns, then you might need to trancate strings if they are longer than the width of the column. Your example can be changed like this:

      Z:\>perl use strict; printf STDOUT "[%-20.20s] [%20.20s]\n", 1000 .. 1001; ^D [1000 ] [ 1001] Z:\>

      Leonid Mamtchenkov aka TVSET

Re: Formatting an output with printf
by Zaxo (Archbishop) on May 27, 2003 at 05:17 UTC

    The old-fashoned way to do this is with format, and it may be the best.

    To do it with printf formats, you will need to construct the format string on the fly, taking account of the length of what you want to print.

    Another way I'd consider is with substr:

    my $line = ' ' x 200; my $cols = { 0 => \$var1, 19 => \$var2, 179 => \$var3, 199 => \$var4 }; for (keys %$cols) { my $val = ${$cols->{$_}}; substr $line, $_, length($val), $val; } print MERGE $line, $/;
    That doesn't conform to the formats you wanted for the indifidual variables, but an extra hash on the same keys and with format strings as values could provide that to my $val = sprintf ... .

    Your $varN variables want to be an array, but I assume the names have been changed to protect the guilty ;-)

    After Compline,
    Zaxo

Re: Formatting an output with printf
by grep (Monsignor) on May 27, 2003 at 05:56 UTC
    Whenever I am thinking about columns and fixed-length data files I think of pack and unpack. I not only find it easier to use but, generally a little faster than printf.
    print MERGE pack('A20A180A200A350',@vars);

    as for the faster part (I thought it would be a bigger difference):

    #!/usr/local/bin/perl use Benchmark; use strict; my $count = 10000; my @lists = map { [chr($_+65),chr($_+66),chr($_+67),chr($_+68) ] } 0.. +22; open(FH1,'>/tmp/x') or die "$!\n"; open(FH2,'>/tmp/y') or die "$!\n"; timethese ($count, { 'pack' => '&use_pack', 'printf' => '&use_printf' +} ); sub use_pack { foreach (@lists) { print FH1 pack('A20A180A200A350',@{$_}); } } sub use_printf { foreach (@lists) { printf FH2 "%-20s%-180s%-200s%-350s", @{$_} ; } }
    Benchmark: timing 10000 iterations of pack, printf... pack: 21 wallclock secs (10.10 usr + 9.55 sys = 19.65 CPU) @ 50 +8.91/s (n=10000) printf: 24 wallclock secs (10.90 usr + 9.72 sys = 20.62 CPU) @ 48 +4.97/s (n=10000) Benchmark: timing 10000 iterations of pack, printf... pack: 21 wallclock secs (10.03 usr + 9.75 sys = 19.78 CPU) @ 50 +5.56/s (n=10000) printf: 23 wallclock secs (11.88 usr + 10.72 sys = 22.60 CPU) @ 44 +2.48/s (n=10000)


    grep
    Mynd you, mønk bites Kan be pretti nasti...
Re: Formatting an output with printf
by Jenda (Abbot) on May 27, 2003 at 21:46 UTC

    You should never (well almost) write

    function( "$var")
    You should use simply
    function( $var)

    If you use the "$var" you are forcing Perl to convert the value of $var to a string and create a copy. This is usualy just a waste of time and memory, but sometimes it actualy breaks the code. If the $var is a reference (or an object ... which is actually also a reference) then Perl creates a string that looks like SCALAR(0x1a4b680). But there is no way to convert this back to a reference. So instead of passing the reference or object you pass a completely useless string.

    Jenda
    Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live.
       -- Rick Osborne

    Edit by castaway: Closed small tag in signature