Convert tabs to spaces in tcl??

Posted on 2008-11-11
Last Modified: 2013-12-21
Using tcl, I'm reading through a file generated by a report-writer. There are some records that have tabs in them, some don't. I need to parse out the fields (columns in the report) positionally. The problem is using string range or crange views the \t in the records as single characters

I tried doing
regsub -all $rec \t "     " rec
but since the amount of whitespace in a tab is not static, I was getting undesired results.

Example of report line:
10/27/08                   801062347       801062347                .00    Charge                  70.99       N
Corresponding example of octal display from the report file:
0001460   \r  \n   1   0   /   2   7   /   0   8                  \t  \t
0001500                8   0   1   0   6   2   3   4   7  \t
0001520    8   0   1   0   6   2   3   4   7  \t  \t                   .
0001540    0   0                   C   h   a   r   g   e  \t  \t
0001560        7   0   .   9   9                               N  \r  \n

I'd prefer to handle this in the tcl script but if necessary, I suppose I can manipulate the file using ksh beforehand, although I'm not sure how I would do that either.

Any ideas?
Question by:sjmont
    LVL 24

    Expert Comment

    Well  this would be a very big suprise. The tab-width does not change. At least this would be the first time I heard of it. As you can see however there are quite a few \t in there. I'd probably go another route just split the line into pieces limited by whitespace. Or you can use another regular expression
    which matches the given text better

    LVL 2

    Expert Comment

    Can this be used:
    % set conv_rec [lrang $rec 0 6]
    10/27/08 801062347 801062347 .00 Charge 70.99 N

    Author Comment

    Yes, that's a valid thought. I guess I should have mentioned that the reason I was parsing the data positionally was because there sometimes is a field missing from the record, for example:


    11/01/08                   801000349       801000349                .00    Charge                  63.00       N

    11/01/08    00566317       801000886       801000886                .00    Charge                  11.25       N

    So in such a case using a list would offset the data in the list elements
    LVL 2

    Expert Comment

    Does defining start and end of each field, then use "string range" work for you? For example:
    set dt_start 0
    set dt_end 7
    set trans_start 8
    set trans_end 19
    set dt [string range $rec $dt_start $dt_end]
    set trans_nu [string range $rec $trans_start $trans_end]
    LVL 2

    Accepted Solution


    Since each field has its own length, replacing each "\t" with a constant number of space is giving you incorrect result, right?

    Do you already know how many spaces to replace "\t" for each field?

    od -t a yourfile.txt
    should have shown how many spaces should be used to replace one "\t" for each field.

    For example:
    When trans_nu comes back missing or doesn't match some rule, a positional replacing "\t\t" with "    \t" (four spaces)

    set conv_rec [join "{[regsub -all \t\t [string range $rec $trans_start $trans_end] "    \t"]} {[string range $rec $cus_start end]}" ""]

    LVL 6

    Expert Comment

    If I understand your quest correctly, you want to replace tabs with spaces while keeping the same "positioning"  as the tabs produce in a terminal?
    The reason for this being that you intend to match the position of the headers with the data fields, or something like that? I think that is also what has been suggested above kind of?

    The attached proceedure could perhaps be of some assistance with replacing tabs with space at least. Probably very slow, but might be good enough for small amounts of data, or you can just use the idea, and write a better performing version :-)
    It simply walks through the original string one char at a time, and if there is a tab at the position it will be substituted with enough spaces to pad up to the next tab-stop (column width defined by the tabstop variable).
    proc tab2space { str } { 
            set tabstop 8 
            set n 0
            set nspc 0 
            set strlen [string length $str]
            while { $n < $strlen } {
                    set c [string index $str $n]
                    if { "$c" == "\t" } {
                            set nn [expr $n + $nspc]
                            set spaces [expr $tabstop - ( $nn % $tabstop )]
                            incr nspc [expr $spaces - 1]
                            append newstr "[string repeat " " $spaces]"
                    } else {
                            append newstr $c
                    incr n
            return "$newstr"

    Open in new window


    Featured Post

    How your wiki can always stay up-to-date

    Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
    - Increase transparency
    - Onboard new hires faster
    - Access from mobile/offline

    Join & Write a Comment

    I hope you'll find this tutorial useful and interesting. So let's try to extend Tcl with a new package.  For anyone more deeply interested please check out the book "Practical Programming in Tcl and Tk". It's really one of the best written books abo…
    How to remove superseded packages in windows w60 or w61 installation media (.wim) or online system to prevent unnecessary space. w60 means Windows Vista or Windows Server 2008. w61 means Windows 7 or Windows Server 2008 R2. There are various …
    Learn the basics of modules and packages in Python. Every Python file is a module, ending in the suffix: .py: Modules are a collection of functions and variables.: Packages are a collection of modules.: Module functions and variables are accessed us…
    The viewer will learn how to count occurrences of each item in an array.

    746 members asked questions and received personalized solutions in the past 7 days.

    Join the community of 500,000 technology professionals and ask your questions.

    Join & Ask a Question

    Need Help in Real-Time?

    Connect with top rated Experts

    14 Experts available now in Live!

    Get 1:1 Help Now