** Summary ** Format a string in the style of sprintf ** Synopsis ** : '''format''' ''formatString'' ?''arg arg ...''? ** Description ** This command generates a formatted string in the same way as the ANSI C sprintf procedure (it uses sprintf in its implementation). FormatString indicates how to format the result, using % conversion specifiers as in sprintf, and the additional arguments, if any, provide values to be substituted into the result. The return value from format is the formatted string. ** Documentation ** [http://www.tcl.tk/man/tcl/TclCmd/format.htm%|%man page]: ** Maximum Width for Numbers ** Note that format, by default, doesn't provide a way to use one of the number formats (like `%d`, etc.) '''AND''' specify a maximum number of digits. You could specify the format as a %s and then provide a maximum number of characters, or you could write tcl code to check for maximum. Jonathan Bromley posted, on comp.lang.tcl during early Sep 2007, this code, which provides a first cut at a "-strict" initial arguement to format. ====== proc strictformat {fmt value} { set f [format $fmt $value] regexp {%(\d+)} $fmt -> maxwidth if {[string length $f]>$maxwidth} { return [string repeat * $maxwidth] } else {return $f} } rename format _format proc format {args} { if {[string equal [lindex $args 0] -strict]} { eval strictformat $args } else { eval _format $args } } ====== ** Make Unsigned Values ** You can use `[[format]` to produce unsigned integers for display (but don't reckon with them - for `[[[expr]]` they're still signed!): ====== % format %u -1 4294967295 ====== See [floating-point formatting] for discussion on how to write format strings to handle floats... [DKF]: Note that 8.5 makes this sort of thing much less necessary as we can now handle arbitrary width integers. ** Nice Looking Floats ** To make numbers look nice: ====== set fah [format "%0.2f" [expr $temperature_cel * 9 / 5 + 32]] ====== ** Color Formatting ** ====== set color [format #%02x%02x%02x $r $g $b] ====== ** Converting Characters ** A limited formatting of decimals to characters is available in other languages, e.g. CHR() in Basic. If you use that more often, here's a cute shortcut: ======none interp alias {} chr {} format %c % set a [chr 49][chr 48] 10 ====== ** Abbreviating Integers ** See [Narrow formatting] for short rendering of big integers, with powers of 1024: ======none % fixform 12345678 11.7M ====== ** Understanding Formats ** This method should get format string and explain the format structure. This is a fast scatch: ====== proc explainFormat {formatStr vars} { set index 1 foreach frm [split $formatStr "%"] { set extra "" set size 0 regexp {([0-9]+)([duioxXcsfegG])(.*)} $frm => size type extra if {$size==0} { set size [string length $frm] } else { set frm "%$size$type [lindex $vars 0]" set vars [lrange $vars 1 end] set size [string trimleft $size 0] } for {set i 0} {$i<2} {incr i} { set newIndex [expr {$size +$index -1}] puts "$index-$newIndex '$frm'" set index [expr {$newIndex +1}] if {$extra==""} { break } else { set frm $extra set size [string length $extra] } } } } ====== ======none % explainFormat hello%02s000%3d $a $b 1-5 'hello' 6-7 '%02s $a' 8-10 '000' 11-13 '%3d $b' ====== ** Emulating Fortran ** [RS] 2007-09-04: Here's emulating the FORTRAN behavior that numbers too large for the format are marked as an asterisk string: ====== proc strictformat {fmt value} { set f [format $fmt $value] regexp {%(\d+)} $fmt -> maxwidth if {[string length $f]>$maxwidth} { return [string repeat * $maxwidth] } else {return $f} } ====== Testing: ======none % strictformat %5.2f 12.345 12.35 % strictformat %5.2f 123.45 ***** % strictformat %5.2f 12345.67 ***** ====== ** Restricting Floats ** While using Tcl 8.5, you will begin to see strings like 0.0052499999999999995 where before you were seeing values like 0.00525. To round the value to a shorter value, try something like: ====== format %.3g 0.0052499999999999995 ====== ** Rebasing ** On comp.lang.tcl, Don Porter writes, in reply to a question about how to go from base 10 to another base, such as 2 or 16, using arbitrarily large numbers in Tcl 8.5: > I would have guessed that "format %x" should do the job, but apparently<
> > it's currently limited to 64 bits... ======none % format %llx 1234567890123456789012345 1056e0f36a6443de2df79 ====== (Note: Those are ELLs above in '%11x'. Not {percent eleven lower-case-x}, but rather {percent, ell, ell, lower-case-x}. [DrASK]) ** Digit Grouping ** Digit grouping can make numbers with many digits easier to read. [ET]: While I never liked the language ADA, it did have an idea that I wish had caught on, the optional use of an underscore character in large numerical constants, to make the numbers readable. (And trival for a compiler or interpreter to scan/parse). So, 1_234_567 is a number that is as readable as 1,234,567 and is much better than 1234567. I have a handy little converter, (which I stole from somewhere on this wiki and modifed): ====== proc {commas} {var {num 3} {char ","}} { set len [string length $var] set first [expr $len - $num] set x "" while { $len > 0} { # grab left num chars set lef [string range $var $first end] if {[string length $x] > 0} { set x "${lef}$char${x}" } else { set x ${lef} } # grab everything except left num chars set var [string range $var 0 [expr $first -1]] set len [string length $var] set first [expr $len - $num] } return $x } ====== Here are some examples of its use: ======none dec2bin 987654 11110001001000000110 % commas [dec2bin 987654] 4 _ 1111_0001_0010_0000_0110 % commas [dec2bin 987654] 4 { } 1111 0001 0010 0000 0110 % commas [dec2bin 987654] 1 { } 1 1 1 1 0 0 0 1 0 0 1 0 0 0 0 0 0 1 1 0 %commas 123456789 ;# naturally, it defaults for use with large decimal integers 123,456,789 % commas 123456789 3 _ ;# and here's how I wish numbers could be entered, in tcl and in C etc. 123_456_789 % puts "0x[commas [format %08X 123456789] 4 _]" ;# and for hex numbers as well 0x075B_CD15 ====== ** Misc ** [LV]: The man page for 8.4 is missing examples. 8.5 is better, but I'm looking for an example of the following. I have a report line that I am trying to fill out. It consists of a time stamp, a date stamp, and 2 text strings. each of these items must begin in a specific column. ====== set g "OHIO" set fmtg [format "%-25.25s" $g] puts [string length "$fmtg"] ====== The man page is complex enough that I want to be certain that I am not missing something. This seems to ensure that if g is longer than 25 characters, it is truncated, and if it is shorter than 25 characters, that it is left justified and blank padded. Are there any ''[gotchas]'' of which I need to be aware? ''[[TODO: Explain XPG positional format specifiers.]]'' <> Tcl syntax help | Arts and crafts of Tcl-Tk programming | Command | Binary Data | String Processing