How to use regsub to grab values after a pattern tcl? - tcl

If I have a variable that has values like this:
set var "/abc/def/ghi/jkl/mno/pqr"
How do I use regsub so that it removes everything except the second last value "mno"?

Well, you can do this:
set updatedValue [regsub {^.*(mno).*$} $value {\1}]
which is an old trick from the Unix utility, sed, translated into Tcl. That will remove everything but the last text to match mno. Pick your RE appropriately.
And don't use this for manipulating filenames, please. It might work, but it makes your code more confusing. The file command has utility subcommands for this sort of work and they handle tricky gotchas that you might not be aware of.

Why a regular expression?
How about:
set val [file tail [file dirname $var]]
References: file

% regexp {.*/([^/]+)/} $var -> val
1
% set val
mno

Try this, Using split and lindex
% set var "/abc/def/ghi/jkl/mno/pqr"
/abc/def/ghi/jkl/mno/pqr
%
% puts "[lindex [split $var "/"] end-1]"
mno

Related

TCL use a variable to generate a varaible and use a variable for file open/close

As an easy example I just want to loop thorugh opening/closing files and use a variable to create another variable. In PERL this is pretty easy but I cnat figure it out in TCL
set gsrs ""
lappend gsrs "sir"
lappend gsrs "dir"
foreach gsr $gsrs {
set file "sdrv/icc/instance_toggle_overwrite.$gsr.txt"
puts "*** I : Generating $file"
set tempGSR gsr
puts "$$tempGSR" # would like output to be value of $gsr
set $gsr [open $file "w"] # normally you would not use a variable here for filename setting
close $$gsr
}
Double-dereferencing is usually not recommended, as it leads to complex code that is quite hard to maintain. However, if you insist on doing it then use set with one argument to do it:
puts [set $tempGSR]
Usually, thinking about using this sort of thing is a sign that either upvar (possibly upvar 0) or an array should be used instead.

how to get specific parameters in a square bracket and store it in to a specific variable in tcl

set_dont_use [get_lib_cells */*CKGT*0P*] -power
set_dont_use [get_lib_cells */*CKTT*0P*] -setup
The above is a text file.
I Want to store */CKGTOP* and */CKTTOP* in to a variable this is the programme which a person helped me with
set f [open theScript.tcl]
# Even with 10 million lines, modern computers will chew through it rapidly
set lines [split [read $f] "\n"]
close $f
# This RE will match the sample lines you've told us about; it might need tuning
# for other inputs (and knowing what's best is part of the art of RE writing)
set RE {^set_dont_use \[get_lib_cells ([\w*/]+)\] -\w+$}
foreach line $lines {
if {[regexp $RE $line -> term]} {
# At this point, the part you want is assigned to $term
puts "FOUND: $term"
}
}
My question is if more than one cells like for example
set_dont_use [get_lib_cells */*CKGT*0P* */*CKOU*TR* /*....] -power
set_dont_use [get_lib_cells */*CKGT*WP* */*CKOU*LR* /*....] -setup
then the above script isn't helping me to store the these "n" number cells in the variable known as term
Could any of u people help me
Thanking you ahead in time
I would go with
proc get_lib_cells args {
global term
lappend term {*}$args
}
proc unknown args {}
and then just
source theScript.tcl
in a shell that doesn't have the module you are using loaded, and thus doesn't know any of these non-standard commands.
By setting unknown to do nothing, other commands in the script will just be passed over.
Note that redefining unknownimpairs Tcl's ability to automatically load some processes, so don't keep using that interpreter after this.
Documentation:
global,
lappend,
proc,
unknown,
{*} (syntax)
Your coding seems like the Synopsys syntax, meaning - it shouldn't work the way you wrote it, I'd expect curly braces:
set_dont_use [get_lib_cells {*/*CKGT*0P* */*CKOU*TR* /*....}] -power
moreover, the \w doesn't catch the *,/ (see this).
If I were you, I'd go for set RE {^set_dont_use \[get_lib_cells \{?([\S*]+ )+\}?\] -\w+$} and treat the resulting pattern match as a list.
Edit:
see this:
% regexp {^set_dont_use [get_lib_cells {?(\S+) ?}?]} $line -> match
1
% echo $match
*/*CKGT*0P*
If you have more than one item in your line, add another parentheses inside the curly braces:
regexp {^set_dont_use \[get_lib_cells \{?(\S+) ?(\S+)?\}?\]} $l -> m1 m2
ect.
Another Edit
take a look at this, just in case you want multiple matches with the same single pattern, but than, instead of \S+, you should try something that looks like this: [A-Za-z\/\*]

How to grep parameters inside square brackets?

Could you please help me with the following script?
It is a Tcl script which Synopsys IC Compiler II will source.
set_dont_use [get_lib_cells */*CKGT*0P*] -power
set_dont_use [get_lib_cells */*CKTT*0P*] -setup
May I know how to take only */*CKGT*0P* and */*CKTT*0P* and assign these to a variable.
Of course you can treat a Tcl script as something you search through; it's just a file with text in it after all.
Let's write a script to select the text out. It'll be a Tcl script, of course. For readability, I'm going to put the regular expression itself in a global variable; treat it like a constant. (In larger scripts, I find it helps a lot to give names to REs like this, as those names can be used to remind me of the purpose of the regular expression. I'll call it “RE” here.)
set f [open theScript.tcl]
# Even with 10 million lines, modern computers will chew through it rapidly
set lines [split [read $f] "\n"]
close $f
# This RE will match the sample lines you've told us about; it might need tuning
# for other inputs (and knowing what's best is part of the art of RE writing)
set RE {^set_dont_use \[get_lib_cells ([\w*/]+)\] -\w+$}
foreach line $lines {
if {[regexp $RE $line -> term]} {
# At this point, the part you want is assigned to $term
puts "FOUND: $term"
}
}
The key things in the RE above? It's in braces to reduce backslash-itis. Literal square brackets are backslashed. The bit in parentheses is the bit we're capturing into the term variable. [\w*/]+ matches a sequence of one or more characters from a set consisting of “standard word characters” plus * and /.
The use of regexp has -> as a funny name for a variable that is ignored. I could have called it dummy instead; it's going to have the whole matched string in it when the RE matches, but we already have that in $term as we're using a fully-anchored RE. But I like using -> as a mnemonic for “assign the submatches into these”. Also, the formal result of regexp is the number of times the RE matched; without the -all option, that's effectively a boolean that is true exactly when there was a match, which is useful. Very useful.
To assign the output of any command <command> to a variable with a name <name>, use set <name> [<command>]:
> set hello_length [string length hello]
5
> puts "The length of 'hello' is $hello_length."
The length of 'hello' is 5.
In your case, maybe this is what you want? (I still don't quite understand the question, though.)
set ckgt_cells [get_lib_cells */*CKGT*0P*]
set cktt_cells [get_lib_cells */*CKTT*0P*]

TCL code to replace () with blank line

Hi i am newbie in TCL please help me with code, method anything. There is a string for example
(abcgfhdskls12345)HELLO(hikjkflklfk)
(bkjopkjjkl)HI(kjkkjjuilpp)
i just want to remove everything between () and want to print only Hi and Hello
You could use Tcl regsub to remove anything with parentheses around it:
set x "(abcgfhdskls12345)HELLO(hikjkflklfk) (bkjopkjjkl)HI(kjkkjjuilpp)"
regsub -all {\(.*?\)} $x {} x
puts $x
which yields:
$ tclsh foo.tcl
HELLO HI
My proposal is to use the regsub command, which performs substitutions based on regular expressions. You can write something like this:
set str {(abcgfhdskls12345)HELLO(hikjkflklfk) (bkjopkjjkl)HI(kjkkjjuilpp)}
set result [ regsub -all {\(.*?\)} $str {} ]
The -all option is required because your pattern may appear more than once in the source string and you don't want to strip just the first.
The text inside {...} is the pattern. You want to match anything that is inside brackets, so you use the \(...\) part; escaping brackets is required because they have a special meaning in the regular expressions syntax.
Inside brackets you want to match any character repeated zero or more times, so you have .*?, where the dot means any character and the *? is the zero-or-more non-greedy repeating command.
You could also split the string on open or close parentheses, and throw out the odd-numbered elements:
set s "(abcgfhdskls12345)HELLO(hikjkflklfk) (bkjopkjjkl)HI(kjkkjjuilpp)"
foreach {out in} [split $s "()"] {puts $out}
HELLO
HI
This is also a way using regexp only.
set p {(abcgfhdskls12345)HELLO(hikjkflklfk) (bkjopkjjkl)HI(kjkkjjuilpp)}
set pol [regexp {(.*)(HELLO)(.*) (.*)(HI)(.*)} $p p1 p2 p3 p4 p5 p6]
puts "$p3 $p6"
o/p: HELLO HI

Grep the word inside double quote

How can I extract a word inside a double quote inside a file?
e.g.
variable "xxx"
Reading a text file into Tcl is just this:
set fd [open $filename]
set data [read $fd] ;# Now $data is the entire contents of the file
close $fd
To get the first quoted string (under some assumptions, notably a lack backslashed double quote characters inside the double quotes), use this:
if {[regexp {"([^""]*)"} $data -> substring]} {
# We found one, it's now in $substring
}
(Doubling up the quote in the brackets is totally unnecessary — only one is needed — but it does mean that the highlighter does the right thing here.)
The simplest method of finding all the quoted strings is this:
foreach {- substring} [regexp -inline -all {"([^""]*)"} $data] {
# One of the substrings is $substring at this point
}
Notice that I'm using the same regular expression in each case. Indeed, it's actually good practice to factor such REs (especially if repeatedly used) into a variable of their own so that you can “name” them.
Combining all that stuff above:
set FindQuoted {"([^""]*)"}
set fd [open $filename]
foreach {- substring} [regexp -inline -all $FindQuoted [read $fd]] {
puts "I have found $substring for you"
}
close $fd
Internal Matching
If you're just looking for a regular expression, then you can use TCL's capture groups. For example:
set string {variable "xxx"}
regexp {"(.*)"} $string match group1
puts $group1
This will return xxx, discarding the quotes.
External Matching
If you want to match data in a file without having to handling reading the file into TCL directly, you can do that too. For example:
set match [exec sed {s/^variable "\(...\)"/\1/} /tmp/foo]
This will call sed to find just the parts of the match you want, and assign them to a TCL variable for further process. In this example, the match variable is set to xxx as above, but is operating on an external file rather than a stored string.
When you just want to find with grep all words in quotes in a file and do something with the words, you do something like this (in a shell):
grep -o '"[^"]*"' | while read word
do
# do something with $word
echo extracted: $word
done