deva
deva

Reputation: 131

how to display output in a uniformed manner in tcl

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

Answers (3)

Hai Vu
Hai Vu

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:

  1. If a field contain space, that field should be quoted with double quote (see Name with space)
  2. the format 2chan command only format fields left-justified. If you are looking into center- or right-justify, then look up the report package.

Upvotes: 4

Donal Fellows
Donal Fellows

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

kostix
kostix

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

Related Questions