TCL grabbing words within special boundaries

﹥>﹥吖頭↗ 提交于 2019-12-25 16:43:25

问题


Objection : get the all words within the "{" "}" boundary.

input_file.txt:

set_false_path -from [get_ports {a/b[1] ab/cd_1 abcd_1_ad_}] -through [get_pins {th/th1 th2/th2[2]}]
set_derate -whatever [get_ports {xxx/xx1 xxx xxxx_1}]
set_false_path 3 -to [get_pins {aaa/d aaa/b}] -from [get_abc {abc/ac/dd nnn_2/2}]

expected output_file.txt:

a/b[1]
ab/cd_1
abcd_1_ad_
th/th1 
th2/th2[2]
aaa/d aaa/b
abc/ac/dd 
nnn_2/2

NB: there might be two or more pair of "{" "}" , and I want to grab all of those words within "{" and "}" no matter how many they are.

here is my code:

set inputfile [open "input_file.txt" r]
set outputfile [open "output_file.txt" w]


while { [gets $inputfile line] != -1 } {
 set first_word [lindex [split $line ""] 0]
  if { regexp "set_false_path" $first_word} {
    # HOW TO grab all words between "{" and "}" ; split them ; put on output_file 
  }
} else {
}

close $inputfile
close $outputfile

回答1:


Since you don't have the lines split on several lines, you can use a simpler script than the previous script:

set inputfile [open "input_file.txt" r]
set outputfile [open "output_file.txt" r]

while {[gets $inputfile line] != -1} {
  # If starts with set_false_path, process
  if {[lindex [split $line " "] 0] eq "set_false_path"} {

    # Grab each element with regexp into a list and print each to outputfile
    # m contains whole match, groups contains sub-matches
    foreach {m groups} [regexp -all -inline -- {\{([^\}]+)\}} $line] {

      # Trim any trailing/leading spaces
      set groups [string trim $groups]
      foreach out [split $groups] {
        puts $outputfile $out
      }
    }
  }

}

close $inputfile
close $outputfile



回答2:


I am submitting two alternate methods just for the sake of variety.

Method 1: Using the unknown Handler

Here is a different approach: since the input file appears to be a Tcl script, as soon as we detect a line with set_false_path, we can evaluate that line in order to extract the PINs. In order for this to work, we setup a procedure called unknown to catch all unknown procedures. In this case, we are interested in get_ports, get_pins, get_abc...:

# proc unknown is invoked for all unknown procedures: those that are
# called without previously defined.
proc unknown {cmdName args} {
    global outFile

    # List of procedures with PINs as arguments
    set pinProcs {get_ports get_pins get_abc}

    # If the procedure has PINs as arguments, we extract those PINs
    # and write to a file
    if {[lsearch -exact $pinProcs $cmdName] != -1} {
        eval "set args $args"; # Remove the surrounding braces {}
        foreach arg $args { puts $outFile $arg }
    }
}

set inFile  [open "input_file.txt"]
set outFile [open "output_file.txt" "w"]
while {[gets $inFile line] != -1} {
    if {[lindex [split $line " "] 0] eq "set_false_path"} {
        eval $line; # Tells Tcl interpreter to interpret the line
    }
}
close $inFile
close $outFile

This method has a couple of advantages: it relies on Tcl to correctly parses the input lines and we don't have to deal with messy regular expressions. The disadvantages include the need to manually keeping track of which procedure we are interested in (see pinProcs, above).

Method 2: Create Our Own set_false_path Procedure

Similar to the above, this time, we setup our own set_false_path procedure to extract all the PINs that follow the following flags: -to, -from, and -through. The advantage of this approach is we don't have to manually keep a list of procedure names (see pinProcs).

# Our own proc, which returns a list of PINs
proc set_false_path {args} {
    set result {}
    for {set i 0} {$i < [llength $args]} {incr i} {
        set token [lindex $args $i]
        if {[lsearch -exact {-to -from -through} $token] != -1} {
            incr i
            set token [lindex $args $i]
            lappend result {*}[lindex $args $i]
        }        
    }
    return $result
}

# proc unknown is invoked for all unknown procedures: those that are
# called without previously defined.
proc unknown {cmdName args} {
    eval "set args $args"; # Remove the surrounding braces {}
    return $args
}

set inFile  [open "input_file.txt"]
set outFile [open "output_file.txt" "w"]
while {[gets $inFile line] != -1} {
    if {[lindex [split $line " "] 0] eq "set_false_path"} {
        foreach pin [eval $line] {
            puts $outFile $pin
        }
    }
}
close $inFile
close $outFile



回答3:


It's working! Thank you very much! you are awesome, dude :)

Here is my final code:

set inputfile [open "input_file.txt" r]
set outputfile [open "output_file.txt" w]

set first_word ""
while { [gets $inputfile line != -1] } {
 if { ([lindex [split $line ""] 0] eq "set_false_path") } {
  foreach {m groups} [regexp -all -inline -- {\{(.+?)\}} $line] {
   foreach out [split $groups] {
    puts $outputfile $out
   }
  }
 }
}

close $inputfile
close $outputfile

input_file.txt:

set_false_path -from [get_ports {a/b[1] ab/cd_1 abcd_1_ad_}] -through [get_pins {th/th1 th2/th2[2]}]
set_derate -whatever [get_ports {xxx/xx1 xxx xxxx_1}]
set_false_path 3 -to [get_pins {aaa/d aaa/b}] -from [get_abc {abc/ac/dd nnn_2/2}]

output_file.txt (all words within {} brackets for all lines starts with "set_false_path"):

a/b[1]
ab/cd_1
abcd_1_ad_
th/th1
th2/th2[2]
aaa/d aaa/b
abc/ac/dd 
nnn_2/2

This forum is great! Thank you Guys! :)

Best regards, Andi Lee



来源:https://stackoverflow.com/questions/21825462/tcl-grabbing-words-within-special-boundaries

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!