
Question:
<strong>Problem</strong> : Expressing the regexp for grabbing words between two boundaries. Below code is not working
regexp -- {/b/{(.+)/}}/b} $outputline8 - filtered
<strong>Objective</strong> :
<ol><li>Grabbing all pin namexxx/xxx[x]
which is located after the
set_false_path
and between {
and }
. </li>
<li>There might be another option such as "-through" in the set_false_path and I still want to grab those pins after those options and put those pins into the output file just as described below.</li>
</ol>Here is my input file : input_file.txt
set_false_path -from [get_ports {AAAcc/BBB/CCC[1] \
BBB_1/CCC[1] CCC/DDD[1] \
DDD/EEE EEE/FFF[1] \
FFF/GGG[1]}] -through\
[get_pins {GGG/HHH[1] HHH/III[1] \
XXX/YYY[1] YYY/XXX[1] \
AAA/ZZZ[1]}]
set_timing_derate -cell_sdada [get_cells \
{NONO[1]}
set_false_path -from [get_ports {AAA/DDD[2]}]
Here is the output file (The format I expected): output_file.txt
AAAcc/BBB/CCC[1]
BBB_1/CCC[1]
CCC/DDD[1]
DDD/EEE
EEE/FFF[1]
FFF/GGG[1]
GGG/HHH[1]
HHH/III[1]
XXX/YYY[1]
YYY/XXX[1]
AAA/ZZZ[1]
AAA/DDD[2]
Generally speaking, those pins don't have any general pattern. So the only way is to grab all pins between {
and }
.
From above input file, we can see that those set_
commands (from the input.txt
) is not connected in a single sentence. So I made a code that will only grab the content within set_false path
and join those lines, below is my code:
set inputfile [open "input_file.txt" r]
set outputfile [open "output_file.txt" w]
set first_word ""
set outputline1 ""
set filtered ""
while { [gets $inputfile line] != 1} {
set first_word [lindex [split $line ""] 0]
set re2 {^set_+?}
#match any "set_ " command
if { [regexp $re2 $first_word matched] } {
#if the "set_ " command is found and the outputline1 is not empty, then it's
# the end of the last set_ command
if {$outputline1 != ""} {
#do the splitting here and put into the outputfile later on
regexp -- {/b/{(.+)/}}/b} $outputline8 - filtered
puts "$filtered:$filtered"
set outputline1 ""
}
# grab content if part of set_false_path
if{ [regexp "set_false_path" $first_word] } {
# if it's the expected command set, put "command_set" flag on which will be used on
# the next elseif
set command_set 1
lappend outputline1 $line
regsub -all {\\\[} $outputline1 "\[" outputline2
regsub -all {\\\]} $outputline2 "\]" outputline3
regsub -all {\\\{} $outputline3 "\{" outputline4
regsub -all {\\\}} $outputline4 "\}" outputline5
regsub -all {\\\\} $outputline5 "\\" outputline6
regsub -all {\\ +} $outputline6 " " outputline7
regsub -all {\s+} $outputline7 " " outputline8
} else {
set command_set 0
# if the line isn't started with set_false_path but it's part of set_false_path command
} elseif {$command_set} {
lappend outputline1 $line
regsub -all {\\\[} $outputline1 "\[" outputline2
regsub -all {\\\]} $outputline2 "\]" outputline3
regsub -all {\\\{} $outputline3 "\{" outputline4
regsub -all {\\\}} $outputline4 "\}" outputline5
regsub -all {\\\\} $outputline5 "\\" outputline6
regsub -all {\\ +} $outputline6 " " outputline7
regsub -all {\s+} $outputline7 " " outputline8
} else {
}
}
}
puts "outputline:outputline8"
#do the splitting here and put into the file later on for the last grabbed line!
close $inputfile
close $outputfile
<strong>Code in-depth discussion:</strong>
<ul><li>I notice that after I <em>lapped</em> the line to <em>outputline1</em>, I will get unexpected output with multiple spaces and forward slash: set_false_path\ -from\ \[get_ports\ \{AAA/BBB\[1\] \
... etc..
This output contains of backspaces (\
) for every special character such as {
, [
, space, etc. So that I put many regsub
to remove all of these unnecessary addition. And the final joined result is located in <em>$outputline8</em>
The result of $outputline8 :
set_false_path -from [get_ports {AAAcc/BBB/CCC[1] BBB_1/CCC[1] CCC/DDD[1] DDD/EEE EEE/FFF[1] FFF/GGG[1]}] -through [get_pins {GGG/HHH[1] HHH/III[1] XXX/YYY[1] YYY/XXX[1] AAA/ZZZ[1]}]
set_false_path -from [get_ports {AAA/DDD[2]}]
</li>
<li>I am planning to grab and split the pin within the <em>outputline8</em> within {
and }
Reference: <a href="https://stackoverflow.com/questions/15872408/process-multiple-lines-text-file-to-print-in-single-line" rel="nofollow">process multiple lines text file to print in single line</a>
<ul><li><strong>HERE IS THE LAST UPDATE START</strong>:
If the input file :
set_false_path -from [get_ports {AAAcc/BBB/CCC[1] BBB_1/CCC[1] DDD/EEE}] -through [get_pins {XXX_1[1]}]
I want the output file:
AAAcc/BBB/CCC[1]
BBB_1/CCC[1]
DDD/EEE
XXX_1[1]
</li>
</ul>Thank you! <strong>HERE IS THE LAST UPDATE END</strong>:
NB: I am new to TCL and this forum and any advice is really appreciated!
Answer1:Try the following script. I have added explanations in the code comments:
set inputfile [open "input_file.txt" r]
set outputfile [open "output_file.txt" w]
# This is a temp variable to store the partial lines
set buffer ""
while { [gets $inputfile line] != -1} {
# Take previous line and add to current line
set buffer "$buffer[regsub -- {\\[[:blank:]]*$} $line ""]"
# If there is no ending \ then stop adding and process the elements to extract
if {![regexp -- {\\[[:blank:]]*$} $line]} {
# Skip line if not "set_false_path"
if {[lindex [split $buffer " "] 0] ne "set_false_path"} {
set buffer ""
continue
}
# 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 -- {\{([^\}]+)\}} $buffer] {
foreach out [split $groups] {
puts $outputfile $out
}
}
# Clear the temp variable
set buffer ""
}
}
close $inputfile
close $outputfile