Beefy Boxes and Bandwidth Generously Provided by pair Networks
Don't ask to ask, just ask
 
PerlMonks  

Re: Printing large numbers with commas to show thousands groups.

by shmem (Chancellor)
on Dec 27, 2019 at 13:48 UTC ( [id://11110659]=note: print w/replies, xml ) Need Help??


in reply to Printing large numbers with commas to show thousands groups.

Of course, there are plenty of potential pitfalls to this simple approach

Here's another approach to that without invocation of a sprintf binary, so no shell danger. Simply interpolate the "babycart operator" @{[]} into the format for any %'d conversion, call sprintf, then eval the result as a string. So something like

cprintf "There are at least %'d ways to do it!\n", 42e6;

will effectively result in

printf "There are at least @{[commify('%d')]} ways to do it!\n", 42e6;

with the difference that, unlike printf, the interpolation is done before the expansion of @{[]}
(printf evaluates the expansion first, i.e. it calls commify with a literal '%d', and then interpolates the value. Bug?)

but without the @{[]} evaluation being done at the time the format is assembled.

All other perl sprintf conversions and flags can be used within the format.

This does the trick:

sub commify { local $_ = shift; my $spc = ''; s/^(\s+)// and $spc = $1; # trim and save leading sp +ace my $adj = 0; $adj++ while s/^([-+]?\d+)(\d{3})/$1,$2/; $spc =~ s/.{$adj}//; # adjust space for commas added s/\s{0,$adj}$// if /\s$/; # adjust right padding return $spc . $_; } sub cprintf { (my $format = shift) =~ s{ \%(['+0-9.-]+)?([df]) # capture all valid %d and %f flags +and modifiers }{ my $p = $1; my $c = $2; $p =~ s/'// ? "\@{[commify('%$p$c')]}" : "%$p$c" }gex; my $str = sprintf $format, @_; print eval "\"$str\""; } cprintf "%+'012d\n", 1e6; cprintf "<%-'12.6d>\n", 1e6; cprintf "<%-+12.6'd>\n", 1e6; cprintf "<%+12.6'd>\n", -1e6; cprintf "<%+12.6d>\n", -1e6; cprintf "<%+12.2'f>\n", 1234.5; cprintf "There are at least %'d ways to do it!\n", 42e6; __END__ +00,001,000,000 <1,000,000 > <+1,000,000 > < +1,000,000> < -1,000,000> < -1000000> < +1,234.50> There are at least 42,000,000 ways to do it!

Of course, neither your nor my approach works for the printf FILEHANDLE FORMAT, LIST form of printf.

update: fixed format substitution

perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'

Replies are listed 'Best First'.
Re^2: Printing large numbers with commas to show thousands groups.
by Anonymous Monk on Dec 27, 2019 at 23:47 UTC
      Hell, yes. There's always somebody who did it better than I could ever do. But! From the OP:
      To modify existing code, just change your printf's to cprintf's and add apostrophe's to the formats as needed. Less work than wrapping each argument with a subroutine call and changing each format to %s. It also helps keep things clear and readable.

      So, my attempt was to provide a solution without shelling out printf. And done, without having to pull in another package and introducing object syntax.

      perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'

        ...And done, without having to pull in another package and introducing object syntax.

        ;) sub printf { ... hide object syntax }

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others cooling their heels in the Monastery: (4)
As of 2024-04-23 07:15 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found