问题
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