Search code examples
tclgtkwave

String pattern matching with tcl


I am new to tcl and am trying to only capture a user-specified hierarchy depth of the following:

top.run.end
top.run.something.end

top.simple.end1     
top.simple.end2

top.simple.something.end1
top.simple.something.end2

top.simple.something.else.end    
top.simple.something.else.other.name.end

I would like to only capture the final element in a hierarchy that does not continue with more elements deliminated by a ".". I.e. I would like to append all instances to a list (final element name could be anything).

If the user wants to select the 2nd hierarchy level, the comparison should only allow these elements from above:

top.run.end
top.simple.end1     
top.simple.end2

If the user specifies the 3rd hierarchy level, then I would like to grab these elements:

top.simple.something.end1
top.simple.something.end2

4th hierarchy level:

top.simple.something.else.end

So on and so forth... I have all the code written except the string comparison, but everything I've tried doesn't seem to do what I want.

set num_hierarchy 3; # how many levels deap to search for "end"
set num_facs      [ gtkwave::getNumFacs ]; # returns number of elements in file

for {set group_to_add 1} {$group_to_add <= $num_hierarchy} {incr group_to_add} {
    set wave [list]

    for {set i 0} {$i < $num_facs } {incr i} {
        set fac_name [ gtkwave::getFacName $i ]; #returns string in form noted above

        set indx [string <how to compare strings??> $fac_name]
        if {$indx == <match>} {
            lappend wave "$fac_name"
        } 
    }
}

Solution

  • I can't say I understand why you are doing the loops like in your question, so I'll show a slightly different code snippet. I believe you should easily be able to implement the solution in your own if I can show you how mine works. The matching is done by counting the number of dots:

    set elements {
      top.run.end
      top.run.something.end
      top.simple.end1     
      top.simple.end2
      top.simple.something.end1
      top.simple.something.end2
      top.simple.something.else.end    
      top.simple.something.else.other.name.end
    }
    
    set depth_required 3
    set wave [list]
    
    foreach element $elements {
      # initial length of element
      set i_len [string length $element]
    
      # final length of element after removing dots
      set f_len [string length [string map {. ""} $element]]
    
      # thus number of dots
      set n_dots [expr {$i_len-$f_len}]
    
      # if the number equals the required hierarchy, then we got one
      if {$n_dots == $depth_required} {
        lappend wave $element
      }
    }
    

    wave then contains:

    top.run.something.end top.simple.something.end1 top.simple.something.end2
    

    You could use regsub (which can directly return the number of substitutions performed) or split the element on dots then count of the number of resulting sub-elements as well, but I found this wiki where it shows using string map is the fastest method overall.