|Perl: the Markov chain saw|
Using (s)printf()by reptile (Monk)
|on Jun 30, 2000 at 03:36 UTC||Need Help??|
printf() and sprintf() work just like in C, with a few slight differences. printf() gives you a lot of control over the formatting of your values, which is what it was intended to do.
If you've ever wanted to make a nicely behaved, field-aligned report, round to an integer or specific decimal place, get octal or hexadecimal representations of your values, or just display your values in any other form imaginable, keep reading. printf() and sprintf() give you the utility to do that, and more.
printf() versus sprintf()
printf() and sprintf() look argumentally the same. That is, whatever arguments you pass to one, you can pass to the other without change. The difference is that printf() prints to a filehandle, and sprintf() returns the string printf() would have outputted.
To use printf() on a filehandle other than STDOUT, specify the filehandle you want to use just as you would with print, like so:
printf(HANDLE $format, @values);
The result will be printed to HANDLE.
sprintf doesn't take a filehandle, but instead returns the output into a string.
my $string = sprintf($format, @values);
The Format String
The format string in printf() is a number of tokens which describe how to print the variables you supply, and whatever else you want. Each variable format specifier starts with a %, is followed by zero or more of the optional modifiers, and ends with a conversion specifier.
A typical format string could look like this:
"foo is %d"
Printed, it may look something like: 'foo is 12'. The %d is replaced by a variable specified after the format string argument. In this case, you would say:
printf("foo is %d", $decimal);
so that %d is replaced with the value of $decimal. You can put as many specifiers in the format string as you like, with the same number of following arguments as there are specifiers. An example:
printf("%d %s %f", $decimal, $string, $float);
You put these in your Format String. Each one, except %%, is replaced by the corresponding value in the printf argument list.
Others that simply exist for backward compatibility:
Each item below is optional (unless otherwise stated), and should be used in the order they appear here. If this is confusing, skip to the next section. It's intended as a reference, and copied from man 3 printf with some extra explanation and examples.
Say you have a number, something like 642, and you want to output it as 00642 instead. The %0nC specifier syntax lets you do just that, where 'n' is the field width, and C is the conversion specifier you want to use. A field width is the minimum (in this case) number of characters the value should fill. Any less than that, and the remainder is filled by prepending zeros on your value until it fits perfectly.
printf("%05d", 642); # outputs '00642'
You should note that certain conversions, like %f, are a little trickier. Floating point numbers (with %f) are always outputted with 6 places after the decimal point, unless you specify a precision with the '.' modifier (see below for a discussion of the '.' precision modifier). In other words, printing a value of '2' as %f will actually output as 2.000000. This means you have to take into account, when specifying the field width, that there are already 7 characters tacked on. To get the value of 2 to print with one leading zero, you have to use a field width of 9 (7 for the '.' and 6 zeros, 1 for the '2', and 1 for the leading zero).
All other specifiers act in this way, too. To find out how many characters are output by default for a specifier, output a value of 0 (zero) for it and count how many characters there are:
# this outputs: '0, 0.000000, 0.000000e+00' printf("%d, %f, %e", 0, 0, 0);
You can also ask perl to count them for you:
printf("There are %d characters\n", length(sprintf("%e", 0)));
Which should tell you there are 12 characters for 0 in scientific notation.
Padding with spaces
This is more or less the same as leading zeros, except it uses leading (or, if told, trailing) spaces to complete the field width. This is useful for lining up multiple lines of data into a report, for instance (though in that case, you may also want to specify a maximum field width to truncate long values - more on that below). The syntax is just like leading zeros, but drop the leading zero:
printf("%6s", 'foo'); # prints ' foo'
By default, leading spaces are used, so values appear to be right-aligned in their field. To reverse this, put a '-' sign before the field width:
printf("%-6s", 'foo'); # prints 'foo '
For numeric values with default precision, like %f and %e, act here just like they do with leading zeros. %f, for example, won't have any padding unless you put a field width of more than 8.
The precision modifier tells printf() how many digits you want after the decimal point, if its a floating point specifier. If there are more digits than you specified, the value is rounded. If there are less, zeros are used to fill the space.
printf("%.2f", 9.333333); # prints '9.34' printf("%.2f", 9); # prints '9.00'
For decimal values, the precision modifier has the same effect as the '0' modifier described above:
printf("%.3f", 7); # prints 007
For string values, it has the nice effect of specifying a maximum field width, where it will only print out the first n characters of the string. In combonation with the field width modifier described above, you can have a well-behaved-under-all-circumstances string field.
printf("%.3s", 'foobar'); # prints 'foo' printf("%.10s", 'foobar'); # prints 'foobar' printf("%5.5s %5.5s", 'foobar', 'baz'); # prints 'fooba baz'
Rounding Numbers with sprintf()
Ever wanted to round a floating point number to a decimal in perl? Or round it to an arbitrary decimal place? sprintf() gives you the ability to do that.
# this sets $foo to '3' $foo = sprintf("%d", 3.14); # this sets $bar to '7.3531' $bar = sprintf("%.4f", 7.35309);
%d specifies to convert the given value to a decimal integer. The conversion rounds as necessary. %.4f specifies to convert the value given to a floating point number with a precision to 4 decimal places, rounding the value as needed.
Octal and Hexadecimal
You can convert your decimal based values to Hexadecimal and Octal values using printf() and sprintf(). To do so, specify the conversion as %o for octal, and %x for hexadecimal. %X is equivilant to %x, except the result is printed using capital letters.
printf("%x", 15); # prints 'f' printf("%X", 15); # prints 'F' printf("%o", 15); # prints '17'
As explained in the Format Modifiers section, using a '#' (pound sign) right after the % will convert the value to "alternate form." For %x and %X, it will prepend to the value '0x' and '0X' respectively. For %o, a single leading '0' (zero) is added. The extra characters using the # modifier are considered part of the field width.
printf("%#x", 15); # prints '0xf' printf("%#o", 15); # prints '017' printf("%#4x", 15); # prints ' 0xf'
In the last example, the field width of 4 is specified. Since the # modifier adds two extra characters to the value, it ends up taking 3 characters in total. Thus the single leading space.
When to Use, and When Not to
While printf() is more powerful than print(), it is also less efficient and more error-prone. The printf manpage tells us not to use printf() where a simple print() would suffice, and that's good advice. You should use printf where you need the control over a value's format that printf() gives you, when you want to use field widths (and don't care much for perl's reports), and when you want to round floating point numbers.
Errors and Corrections
Please post any errors and corrections below. I'll humbly and embarassingly admit my mistake and fix it. Helpful comments would be greatly appreciated.