Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things
 
PerlMonks  

Possible to use variable in printf statement?

by mmartin (Monk)
on Aug 05, 2011 at 18:25 UTC ( #918845=perlquestion: print w/replies, xml ) Need Help??

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


Hello Monks,

I was wondering if it is possible to use a variable in a printf statement in the "format string"? And if not is there a workaround to do this?

For example, I'm printing out a set of data in the form of a table. Each line either has 10 to 11 columns. I was using this to print the data to my file:

printf OUTDATA "%-12s ", $AoA[$x][$y];
Which as you all know prints columns at a width of 12. So I'm wondering if it is possible to replace the '12' with a variable? Like this:

#Variable would be --> $varLength printf OUTDATA "%-$varLengths ", $AoA[$x][$y];



Any suggestions would be greatly appreciated. I want to do this because the columns could have anywhere from 1 char to about 12 chars long, and having a column of length 12 for a string that is only 1 character doesn't look very good when the data is stretched across the screen.


Thanks in Advance,
Matt


Replies are listed 'Best First'.
Re: Possible to use variable in printf statement?
by toolic (Bishop) on Aug 05, 2011 at 18:35 UTC
    Yes, it is possible. One way to do it...
    my $v = 20; printf "%${v}s", 'foo';
Re: Possible to use variable in printf statement?
by ikegami (Patriarch) on Aug 05, 2011 at 18:41 UTC
    It's just a string like any other. You can build it however you want.
    printf "%-".$width."s ", $AoA[$x][$y]; printf "%-${width}s ", $AoA[$x][$y];

    You can also use "*":

    printf "%-*s ", $width, $AoA[$x][$y]; printf "%*s ", -$width, $AoA[$x][$y];
Re: Possible to use variable in printf statement?
by BrowserUk (Patriarch) on Aug 05, 2011 at 18:41 UTC

    See the printfdocs for the use '*' in a format specifier:

    [0] Perl> printf "%*s\n", $_, 'hello' for 10 .. 20;; hello hello hello hello hello hello hello hello hello hello hello

    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.
Re: Possible to use variable in printf statement?
by JavaFan (Canon) on Aug 05, 2011 at 21:19 UTC
    I was wondering if it is possible to use a variable in a printf statement in the "format string"?
    What happened when you wrote the one-liner to try this out?

      I'm also curious to know: What happened when mmartin took a look at the sprintf documentation?

        The world may never know ... but I look forward to that wondrous day!

Re: Possible to use variable in printf statement?
by mmartin (Monk) on Aug 08, 2011 at 15:25 UTC

    Hey Guys, thanks for the replies.


    toolic, ikegami, BrowserUK:
    Thanks for the suggestions I will give them a try, but it looks like that is exactly what I need, Thanks!!!

    JavaFan,
    what one-liner? Sorry I must have missed something? Was that question for me?

    AnomalousMonk,
    I did read through the sprintf perldocs and did not find anything like what the users above had mentioned. i.e. ${x}
    I did see though something like, ' *2$ ' but not the aforementioned one.


    Thanks again,
    Matt

    .

      It took a bit of looking. I went to printf (which directed me to sprintf) but I eventually found the syntax examples applicable to your purpose, dynamically sizing the output mask. We can't always get by with just scanning the docs. A function like printf has so many options, you really need to bite the bullet and slog your way through it, line by line, to find the particular one you need. If it isn't there, it's a fair indication you are using the wrong function. But I learned something from your question (and I am hopefully helping you as well).

      It is up to you to decide which will be easier to decipher when you come back to this 6 months from now and can't recognize your own code ;) Do you want to (1) always supply the sizing variable as the first parameter or (2) do you want the flexibility to be able to use any parameter in the list?

      Case 1:

      printf OUTDATA "%-*s ",$varlength, $AoA[$x][$y];

      Case 2: using the 3rd variable

      printf OUTDATA "%-*3\$s %s %4\$s ",$AoA[$x][$y], $extravar, $varlength, $othervar;
Re: Possible to use variable in printf statement?
by TomDLux (Vicar) on Aug 08, 2011 at 17:48 UTC

    What no one has explicitly said in so many words is, when you try to introduce the variable with the width intot he format string, you have to distinguish that from the 's' specifying the substitution of an external string. When you have "%-$varLengths ", it looks like the variable $varLengths with no 's' after it. This kind of "butting strings together" happens in other situations, for example generating file names. You can either use '.' concatenation of separate variables, rather than having everthing in one string, or else use curly braces to limit the extent of variable names.

    In format strings, using '*' for the width and specifying it with the other variables is probably better; you don't need to alter the format string to handle different widths.

    As Occam said: Entia non sunt multiplicanda praeter necessitatem.

Re: Possible to use variable in printf statement?
by mmartin (Monk) on Aug 08, 2011 at 20:47 UTC

    GotToBTru,

    Thanks for the response. Yes the first case I did read about that. But whenever I tried using it my script would execute and then never stop... Weird, would not stop printing blank lines in my terminal? Don't know why. But you second case is interesting I'll have to take a look into that. Thanks again!


    TomDLux,

    Gotcha, thanks for the reply. Makes sense...



    Thanks to everyone who responded.
    Here is what I ended up doing:

    my @colLength; sub calcMaxColumn { # $i will hold index locations of column lengths in the array @co +lLengths. my $i; # Loop through the array @AoA. And if the length of the current c +olumn is greater then the length of the # same column in the previous row then set the greater number equ +al to that location in @colLength. for (my $x = 0; $x <= $#AoA; $x++) { $i = 0; for (my $y = 0; $y <= 11; $y++) { if ($colLengths[$i] < length($AoA[$x][$y])) { $colLengths[$i] = length($AoA[$x][$y]); } $i++; } } }


    So basically I created the sub routine above that calculates the longest length of the string in each column. Then I used what you guys showed me, to use a variable (in my case $colLength[]) to format the output.


    And here is how I printed:
    my $strLen = 0; for (my $x = 0; $x <= $#AoA; $x++) { #If the current line is an owner then there will only be 10 el +ements. if ($AoA[$x][0] eq 'OWNER') { $waitline = 10; } #ELSE the line is a user waiting and we should add the time wa +iting to the end of that line, 11 total elements. else { $waitline = 11; } for (my $y = 0; $y <= $waitline; $y++) { $strLen = $colLengths[$y]; printf OUTDATA "%-${strLen}s ", $AoA[$x][$y]; } print OUTDATA "\n"; }


    It works great!!! Thanks again guys. your the bestest...

    Thanks,
    Matt

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others chanting in the Monastery: (3)
As of 2022-08-09 19:21 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found

    Notices?