Tcl Part I · Module 5 · Strings
format: Producing Output You Can Line Up
Two problems come up constantly in any script that produces output for a person to read: making columns line up, and showing a number to a sensible number of decimal places. This command solves both, and it is worth learning properly rather than copying patterns, because the syntax has a simple structure underneath it. A conversion is four optional parts in a fixed order, and once you can see that structure you can write any conversion you need instead of recognising the four you have seen before.
Foundation13 min readTclPart IStringsformatOutput
Part I · Module 5 · Chapter 5.11 · format: Producing Output You Can Line Up
1. The Shape
puts [format "name: %s count: %d" "widget" 42]name: widget count: 42The first argument is a format string: literal text with conversions marked by %. The remaining arguments fill those conversions, in order.
Everything that is not a conversion is copied through exactly.
2. The Common Types
puts [format "%s" "text"]
puts [format "%d" 42]
puts [format "%f" 3.5]
puts [format "%e" 12345.678]
puts [format "%x and %X" 255 255]
puts [format "%o" 8]
puts [format "%c" 65]
puts [format "100%%"]text
42
3.500000
3.500000e+00
ff and FF
10
A
100%| Conversion | Produces |
|---|---|
%s | the value as text |
%d | a whole number |
%f | a real number, six decimal places by default |
%e | scientific notation |
%x %X | hexadecimal, lower or upper case |
%o | octal |
%c | the character with that code |
%% | a literal percent sign |
Note %f gave 3.500000. Six decimal places is the default and is almost never what you want, which is §4.
3. Width and Alignment
A number after the % sets a minimum width:
puts [format "|%10s|" "right"]
puts [format "|%-10s|" "left"]
puts [format "|%10d|" 42]| right|
|left |
| 42|Right-aligned by default; a minus sign aligns left. The width is a minimum — longer values are not truncated.
This is what makes a table:
puts [format "%-14s %8s" "SIGNAL" "WIDTH"]
puts [format "%-14s %8s" "--------------" "--------"]
foreach {name width} {clk 1 reset 1 data_valid 1 payload 64} {
puts [format "%-14s %8d" $name $width]
}SIGNAL WIDTH
-------------- --------
clk 1
reset 1
data_valid 1
payload 64Names left-aligned in 14 characters, numbers right-aligned in 8. That is the whole technique, and it replaces the manual padding of Chapter 5.2 §6.
4. Decimal Places
A dot and a number set the precision:
puts [format "%f" 3.14159]
puts [format "%.2f" 3.14159]
puts [format "%.0f" 3.14159]
puts [format "%8.3f" 3.14159]3.141590
3.14
3
3.142%.2f is the one you will use most. It is the correct answer to "round this for display", which Chapter 4.8 §5 and Chapter 4.10 §7 both deferred to this chapter.
With %s, precision truncates instead:
puts [format "%.5s" "truncated"]trunc5. Flags
The optional characters right after %:
puts [format "%05d" 42]
puts [format "%+d %+d" 5 -5]
puts [format "%-8d|" 42]
puts [format "% d" 42]00042
+5 -5
42 |
42| Flag | Effect |
|---|---|
- | align left |
0 | pad with zeros instead of spaces |
+ | always show a sign |
| space | show a space where a plus would be |
%05d is how you produce a zero-padded identifier — 00042.
6. The Full Structure
Putting it together, a conversion has four optional parts in a fixed order:
% -0+ 10 .3 f
│ │ │ │
│ │ │ └── type (required)
│ │ └─────────── precision (optional)
│ └─────────────────── width (optional)
└─────────────────────────── flags (optional)puts [format "|%-10.3f|" 3.14159]
puts [format "|%+08.2f|" 3.14159]|3.142 |
|+0003.14|Read any conversion left to right in that order and it stops being cryptic.
7. Width From a Variable
A * takes the width from an argument:
set w 6
puts [format "|%*d|" $w 42]| 42|Useful when the column width is computed — for instance from the longest name in a list.
8. Common Mistakes
Wrong number of arguments. Each conversion consumes one, so a stray % shifts everything after it.
Using %d on a real number. It is an error, not a truncation. Convert with int() first.
Forgetting %% for a literal percent. A lone % followed by a letter is read as a conversion.
Using %f without a precision. Six decimal places is rarely what you meant. §2.
Expecting width to truncate. It is a minimum. Use a precision with %s to cut text. §4.
Reading back a %05d value as a number. It is octal. §5.
9. Exercises
Exercise 1 — the types. Produce, from the value 255: the decimal form, lowercase hex, uppercase hex, and octal.
Exercise 2 — a table. Print a three-column table of name, count and percentage for four rows, with names left-aligned in 12 characters, counts right-aligned in 6, and percentages to one decimal place.
Exercise 3 — zero padding. Produce 007, 0042 and 00000. Then read 007 back with expr and explain the result.
Exercise 4 — read the conversion. Without running, say what each produces for the value 3.14159: %6.2f, %-6.2f, %+.4f, %08.1f.
Exercise 5 — percent sign. Print completed: 75% where the 75 comes from a variable.
Exercise 6 — compute the width. Given the names {clk reset data_valid}, find the longest with string length, then use %*s to print all three in a column exactly that wide.
10. Remember
- A format string is literal text plus conversions, and each conversion consumes one argument.
- Types:
%s%d%f%e%x%o%c, and%%for a literal percent. - A number is a minimum width, right-aligned;
-aligns left. - A dot and a number set precision — decimal places for
%f, truncation for%s. %.2fis the right way to round for display. It produces text and does not change the value.- Flags are
-0+and space, and%05dgives zero padding. - The order is flags, width, precision, type.
*takes the width from an argument.- A zero-padded number read back by
expris octal.
Next: taking a formatted line apart again.
Where this fits
Part of the Tcl curriculum.
