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

I am printing some decimal and floating point numbers using printf. For most cases I have data, but sometimes the columns are zero, or the denominator is zero. I have successfully captured these "divide by zero" conditions, but now seek help with the format.

I would like the zeros to be blank in the columns # Calls, and Dur/Call, as in the unaccounted-for line below.

Also, my input locale doesn't put a thousands separator comma for the # Calls column. I tried "use locale", but I'm really at a loss here.

Thanks for the help.

Here is the output:

Response Time Component                Duration     # Calls   Dur/Call
------------------------------- ---------------- ---------- ----------
db file sequential read             8.98s  84.8%       3120  0.0028780
CPU service                         1.25s  11.8%         11  0.1136364
unaccounted-for                     0.35s   3.3%          0  0.0000000
SQL*Net message from client         0.01s   0.1%          5  0.0018424
SQL*Net message to client           0.00s   0.0%          5  0.0000028
------------------------------- ---------------- ---------- ----------
Total response time               10.59s  100.0%
use strict; use warnings; my $DEBUG = (shift @ARGV || 0); my $version = 100; # pre-Oracle9i input data is centi-seconds. my %cid; # cursor id of recursive cursors. my %ela; # $ela{event} contains sum of ela statistics for e +vent my %ctr; # $ctr{event} contains count of events my $sum_ela = 0; # sum of all ela times across events my $r = 0; # response time for database call my $action = "(?:PARSE|EXEC|FETCH|UNMAP|SORT UNMAP)"; while (<>) { if (/^(Oracle9i)/) { $version = 1000000; # Oracle9i input data is micro +-seconds. print "version $1 trace data found\n" if $DEBUG; } if (/^PARSING IN CURSOR #(\d+) len=(\d+) dep=(\d+)/i) { $cid{$1} = $3; print "Cursor #$1 is recursive level $cid{$1}\n" if $DEBUG; } if (/^WAIT #(\d+): nam='([^']*)' ela=\s*(\d+)/i) { if (!defined $cid{$1} || $cid{$1} == 0) { # check dep= value for complete trace input only $ctr{$2}++; $ela{$2} += $3; $sum_ela += $3; } } elsif (/^$action #(\d+):c=(\d+),e=(\d+),p=(\d+),cr=(\d+),cu=(\d+), +mis=(\d+),r=(\d+),dep=(\d+)/i) { if (!defined $cid{$1} || $cid{$1} == 0) { # check dep= value for complete trace input only $ctr{"CPU service"}++; $ela{"CPU service"} += $2; $r += $3; } } } $ela{"unaccounted-for"} = $r - ($ela{"CPU service"} + $sum_ela); $ctr{"unaccounted-for"} = 0; printf "\n%-30s %16s %10s %10s\n", "Response Time Component", "Duration", "# Calls", "Dur/Call"; printf "%30s- %16s %10s %10s\n", "-"x30, "-"x16, "-"x10, "-"x10; printf "%-30s %8.2fs %5.1f%% %10d %8.7f\n", $_, $ela{$_}/$version, $ela{$_}/$r*100, $ctr{$_}, ($ctr{$_} && $ela{$_}/$ctr{$_}/$version ||0) for sort { $ela{$b} <=> $ela{$a} } keys %ela; printf "%30s- %16s %10s %10s\n", "-"x30, "-"x16, "-"x10, "-"x10; printf "%-30s %8.2fs %5.1f%%\n\n", "Total response time", $r/$version +, 100;

Replies are listed 'Best First'.
Re: printf format to blank
by tachyon (Chancellor) on Sep 07, 2004 at 04:40 UTC

    The solution is to format it in two passes. In pass 1 you map your data to what you want ie 1,234.00 or '' for a 0 result using sprintf, a commify sub, and some logic. In your printf you simply render this data in the desired columns using %Ns for all data. Perl will happily stringify the formatted numbers. You could also use a format

    You might SuperSearch for commify for numerous ways to add commas, but be aware not all of them deal with floats correctly. Something along these lines should do the trick:

    printf "%-30s %11ss %7s%% %10s %16s\n", $_, $ela{$_} ? commify( sprintf( "%8.2f", $ela{$_}/$version ) ) + : '', $ela{$_} ? commify( sprintf( "%5.1f", $ela{$_}/$r*100) ) + : '', $ctr{$_} ? commify( sprintf( "%10d", $ctr{$_} ) ) + : '', $ctr{$_} && $ela{$_} ? sprintf( "%8.7f", $ela{$_}/$ctr{$_}/$versio +n ): ''; sub commify { local $_ = reverse shift; /\./g; s/\G(\d{3})(\d)/$1,$2/g; scalar reverse $_ }

    You need to allow for potential extra field width from the commas of course.

    cheers

    tachyon

      thanks. It all works great!!!