Search code examples
dictionarydata-structurestclassociative-arraytclsh

Write into tcl dictionary


I am relatively new to tcl dictionaries and don't see a good documentation on how to initialize an empty dictionary, loop over a log and save data into it. Finally I want to print a table that looks like this:

 - Table:

HEAD1
  Step 1    Start Time     End Time

  Step 2    Start Time     End Time

**

 - Log:

    **

    HEAD1
      Step1
         Start Time : 10am
         .
         .
         .
         End Time: 11am

      Step2
         Start Time : 11am
         . 
         .
         End time : 12pm

    HEAD2
      Step3
         Start Time : 12pm
         .
         .
         .
         End Time: 1pm

      Step4
         Start Time : 1pm
         . 
         .
         End time : 2pm

Solution

  • You really don't have to initialise an empty dictionary in Tcl - you can simply start using it and it will get populated as you go along. As mentioned already, dict man page is the best way to start. Additionally, I would suggest you check the regexp man page as you can use it nicely to parse your text file.

    Not having anything better to do atm, I cobbled together a short sample code that should get you started. Use it as a starting tip, adjust it to your particular log layout and add some defensive measures to prevent errors from unexpected input.

    # The following line is not strictly necessary as Tcl does not
    # require you to first create an empty dictionary.
    # You can simply start using 'dict set' commands below and the first
    # one will create a dictionary for you.
    # However, declaring something as a dict does add to code clarity.
    
    set tableDict [dict create]
    
    # Depending on your log sanity, you may want to declare some defaults
    # so as to avoid errors in case the log file misses one of the expected
    # lines (e.g. 'HEADx' is missing).
    
    set headNumber {UNKNOWN}
    set stepNumber {UNKNOWN}
    set start {UNKNOWN}
    set stop {UNKNOWN}
    
    # Now read the file line by line and extract the interesting info.
    # If the file indeed contains all of the required lines and exactly
    # formatted as in your example, this should work.
    # If there are discrepancies, adjust regex accordingly.
    
    set log [open log.txt]
    while {[gets $log line] != -1} {
        if {[regexp {HEAD([0-9]+)} $line all value]} {
            set headNumber $value
        }
        if {[regexp {Step([0-9]+)} $line all value]} {
            set stepNumber $value
        }
        if {[regexp {Start Time : ([0-9]+(?:am|pm))} $line all value]} {
            set start $value
        }
    
        # NOTE: I am assuming that your example was typed by hand and all
        # inconsistencies stem from there. Otherwise, you have to adjust
        # the regular expressions as 'End Time' is written with varying
        # capitalization and with inconsistent white spaces around ':'
    
        if {[regexp {End Time : ([0-9]+(?:am|pm))} $line all value]} {
            set start $value
    
            # NOTE: This short example relies heavily on the log file
            # being formatted exactly as described. Therefore, as soon
            # as we find 'End Time' line, we assume that we already have
            # everything necessary for the next dictionary entry
    
            dict set tableDict HEAD$headNumber Step$stepNumber StartTime $start
            dict set tableDict HEAD$headNumber Step$stepNumber EndTime $stop
        }
    }
    close $log
    
    
    # You can now get your data from the dictionary and output your table
    
    foreach head [dict keys $tableDict] {
        puts $head
        foreach step [dict keys [dict get $tableDict $head]] {
            set start [dict get $tableDict $head $step StartTime]
            set stop [dict get $tableDict $head $step EndTime]
            puts "$step   $start   $stop"
        }
    }