4 Presenting Large Numbers Attractively


#4 Presenting Large Numbers Attractively

A common mistake that programmers make is to present the results of calculations to the user without first formatting them. It's difficult for users to ascertain whether 43245435 goes into the millions without manually counting from right to left and mentally inserting a comma every three digits. Use this script to format your results.

The Code

 #!/bin/sh # nicenumber -- Given a number, shows it in comma-separated form. # Expects DD and TD to be instantiated. Instantiates nicenum # or, if a second arg is specified, the output is echoed to stdout. nicenumber() {   # Note that we assume that '.' is the decimal separator in   # the INPUT value to this script. The decimal separator in the output value is   # '.' unless specified by the user with the -d flag   integer=$(echo   cut -d. -f1)              # left of the decimal   decimal=$(echo   cut -d. -f2)              # right of the decimal   if [ $decimal !=  ]; then     # There's a fractional part, so let's include it.     result="${DD:="."}$decimal"   fi   thousands=$integer   while [ $thousands -gt 999 ]; do     remainder=$(($thousands % 1000))    # three least significant digits     while [ ${#remainder} -lt 3 ] ; do  # force leading zeros as needed       remainder="0$remainder"     done     thousands=$(($thousands / 1000))    # to left of remainder, if any     result="${TD:=","}${remainder}${result}"    # builds right to left   done   nicenum="${thousands}${result}"   if [ ! -z  ] ; then     echo $nicenum   fi } DD="." # decimal point delimiter, to separate integer and fractional values TD="," # thousands delimiter, to separate every three digits while getopts "d:t:" opt; do   case $opt in     d ) DD="$OPTARG"    ;;     t ) TD="$OPTARG"    ;;   esac done shift $(($OPTIND - 1)) if [ $# -eq 0 ] ; then   echo "Usage: $(basename 
 #!/bin/sh # nicenumber -- Given a number, shows it in comma-separated form. # Expects DD and TD to be instantiated . Instantiates nicenum # or, if a second arg is specified, the output is echoed to stdout . nicenumber() { # Note that we assume that '.' is the decimal separator in # the INPUT value to this script. The decimal separator in the output value is # '.' unless specified by the user with the -d flag integer=$(echo $1  cut -d. -f1) # left of the decimal decimal=$(echo $1  cut -d. -f2) # right of the decimal if [ $decimal != $1 ]; then # There's a fractional part, so let's include it. result="${DD:="."}$decimal" fi thousands=$integer while [ $thousands -gt 999 ]; do remainder=$(($thousands % 1000)) # three least significant digits while [ ${#remainder} -lt 3 ] ; do # force leading zeros as needed remainder="0$remainder" done thousands=$(($thousands / 1000)) # to left of remainder, if any result="${TD:=","}${remainder}${result}" # builds right to left done nicenum="${thousands}${result}" if [ ! -z $2 ] ; then echo $nicenum fi } DD="." # decimal point delimiter , to separate integer and fractional values TD="," # thousands delimiter, to separate every three digits while getopts "d:t:" opt; do case $opt in d ) DD="$OPTARG" ;; t ) TD="$OPTARG" ;; esac done shift $(($OPTIND - 1)) if [ $# -eq 0 ] ; then echo "Usage: $(basename $0) [-d c] [-t c] numeric value" echo " -d specifies the decimal point delimiter (default '.')" echo " -t specifies the thousands delimiter (default ',')" exit 0 fi nicenumber $1 1 # second arg forces nicenumber to 'echo' output exit 0 
) [-d c] [-t c] numeric value" echo " -d specifies the decimal point delimiter (default '.')" echo " -t specifies the thousands delimiter (default ',')" exit 0 fi nicenumber 1 # second arg forces nicenumber to 'echo' output exit 0

How It Works

The heart of this script is the while loop within the nicenumber function, which takes the numeric value and iteratively splits it into the three least significant digits (the three that'll go to the right of the next comma) and the remaining numeric value. These least significant digits are then fed through the loop again.

Running the Code

To run this script, simply specify a very large numeric value, and the script will add a decimal point and thousands separators as needed, using either the default values or the characters specified as flags.

Because the function outputs a numeric result, the result can be incorporated within an output message, as demonstrated here:

 echo "Do you really want to pay $(nicenumber $price) dollars?" 

The Results

 $  nicenumber 5894625  5,894,625 $  nicenumber 589462532.433  589,462,532.433  $ nicenumber -d, -t. 589462532.433  589.462.532,433 

Hacking the Script

Different countries use different characters for the thousands and decimal delimiters, hence the addition of flexible calling flags to this script. For example, Germans and Italians would use - d "." and - t "," . The French use - d "," and -t" " , and the Swiss, who have four national languages, use - d "." and - t "'" . This is a great example of a situation in which flexible is better than hard-coded, so that the tool is useful to the largest possible user community.

On the other hand, I did hard-code the "." as the decimal separator for input values, so if you are anticipating fractional input values using a different delimiter, you can change the two calls to cut that specify a "." as the decimal delimiter. Here's one solution:

 integer=$(echo   cut "-d$DD" -f1)      # left of the decimal decimal=$(echo   cut "-d$DD" -f2)      # right of the decimal 

This works, but it isn't particularly elegant if a different decimal separator character is used. A more sophisticated solution would include a test just before these two lines to ensure that the expected decimal separator was the one requested by the user. We could add this test by using the same basic concept shown in Script #2: Cut out all the digits and see what's left:

 separator="$(echo   sed 's/[[:digit:]]//g')" if [ ! -z "$separator" -a "$separator" != "$DD" ] ; then   echo " 
 separator="$(echo $1  sed 's/[[:digit:]]//g')" if [ ! -z "$separator" -a "$separator" != "$DD" ] ; then echo "$0: Unknown decimal separator $separator encountered ." >&2 exit 1 fi 
: Unknown decimal separator $separator encountered." >&2 exit 1 fi



Wicked Cool Shell Scripts. 101 Scripts for Linux, Mac OS X, and Unix Systems
Wicked Cool Shell Scripts
ISBN: 1593270127
EAN: 2147483647
Year: 2004
Pages: 150
Authors: Dave Taylor

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net