Reputation: 131
I have a doubt regarding format
command. my output is kind of cluster and ununiform like below
24-04-2011 16:07 <DIR> Administrator
15-05-2011 16:05 <DIR> confuser
01-02-2011 20:57 <DIR> Public
What should I do in order to display the output in a proper and uniform manner. all in beginning in the same column. like this :
Yeah i used this command puts [format {%-s %-4s %-8s} $user\t $date\t $time]
its giving me output like:
Administrator 15-05-2011 16:05
confuser 01-02-2011 20:57
Public 29-01-2011 19:28
TechM 30-04-2011 09:47
The output am receiving is according to the number of letters present in the first string such as administrator confuser public techm. so what i need to know is how to get a output which doesn't take into account the length of the first string and give a proper uniform columned output.
Upvotes: 4
Views: 12290
Reputation: 40733
The easiest way to solve this problem is to use the struct::matrix package, part of tcllib:
package require struct::matrix
set lines {
{Administrator 15-05-2011 16:05}
{confuser 01-02-2011 20:57}
{Public 29-01-2011 19:28}
{TechM 30-04-2011 09:47}
{"Name with space" 29-04-2011 11:05}
}
struct::matrix m; # Create a new matrix
m add columns 3; # The matrix has 3 columns: file name, date, and time
foreach line $lines {
m add row $line; # Add a line to the matrix
}
m format 2chan; # Prints it out
Output:
Administrator 15-05-2011 16:05
confuser 01-02-2011 20:57
Public 29-01-2011 19:28
TechM 30-04-2011 09:47
Name with space 29-04-2011 11:05
Notes:
Upvotes: 4
Reputation: 137587
The cheap hack method is to use tabs as separators (“\t
” instead of “”) in your output string. That will work for small amounts of variation, but won't handle wide variations (or small variations around your current terminal/editor's tab width).
To do the job properly, you need to first get a list of all the conceptual lines you want to print out (i.e., the data but not yet formatted). Then you go through each line and work out the width needed for each field, taking the maximum across the whole dataset. With that, you can then configure the format string for format
. Here's an example (for Tcl 8.5) where everything is just being formatted as strings:
proc printColumnarLines {lines} {
foreach fields $lines {
set column 0
foreach field $fields {
set w [string length $field]
if {![info exist width($column)] || $width($column) < $w} {
set width($column) $w
}
incr column
}
}
foreach fields $lines {
set column 0
foreach field $fields {
puts -nonewline [format "%-*s " $width($column) $field]
incr column
}
puts ""; # Just the newline please
}
}
The *
in the format string in that position means to take another argument specifying the width of that field. I'm not surprised you missed it though; format strings are actually a very dense micro-language and it is easy to skip over an important bit. (That's true for all other languages that use them too; very few people know all that you can do with them.)
You can do much more intelligent things with fixed sets of fields, and other %
-sequences support the *
too. Mind you, I usually have to experiment to get exactly what I want (especially with floating point numbers…)
Upvotes: 7
Reputation: 55473
You have to first collect all the records to be displayed, then find the size of the longest string to be placed in the first output column; let's call it max_len
. Then, knowing that size, you pad each string to be output in the first column with that many space characters on the right (at the end of the string, that is) for the resulting total length to be exactly max_len
(hint: use string repeat " " [expr {$max_len - [string length $s]}]
to construct a padding chunk) then use that padding to output the string.
By the way, you can see how the parray
standard command is implemented as it does exactly what you want. To see its implementation, execute
set x {Administrator foo Molly bar Dolly blorb}
parray x
info body parray
in an interactive Tcl shell prompt (tkcon is recommended for this).
Upvotes: 2