I'm trying to have a very generic function and ordering it to use variables it come across from the outside.
I've tried the following (simplified code), but with no use:
set line "found \$find1 at \$find2"
do_search $line
proc do_search {line} {
...
if {[regexp $exp $string match find1 find2} {
puts "$line"
}
However all I get is: found $find1 at $find2 or, if I don't use the \ before the $find, the value of find before I call the function.
Given that this regexp is part of a while loop while parsing a file, I can't use the values after the proc is called.
Any ideas how can it be done?
For your exact style, you want subst:
if {[regexp $exp $string match find1 find2} {
puts [subst $line]
}
But you might consider using format too:
set fmt "found %s at %s"
do_search $fmt
proc do_search {fmt} {
...
if {[regexp $exp $string match find1 find2} {
puts [format $fmt $find1 $find2]
}
Related
Suppose I have a string which is also a Tcl command.
set line {lsort -unique [list a b c a]}
How can I convert this string into a list equivalent to this?
{
{lsort}
{-unique}
{[list a b c a]}
}
Because of whitespace inside the square brackets, I can't just use lindex.
For example:
> lindex $line 2
--> [list
The reason I'm asking is because I have a large Tcl script that I want to parse and re-write. I would like certain lines in the re-written script to have swapped argument order or some numerical arguments scaled by a factor.
I know I could parse the string character by character, keeping track of {}, [], and " characters, but this feels like re-inventing something that might already exist. I've been looking at the info and interp commands but couldn't find anything there.
I used info complete successfully in this proc.
proc command_to_list {command} {
# split by whitespace
set words [regexp -all -inline {\S+} $command]
set spaces [regexp -all -inline {\s+} $command]
set output_list [list]
set buffer ""
foreach word $words space $spaces {
append buffer $word
if {[info complete $buffer]} {
lappend output_list $buffer
set buffer ""
} else {
append buffer $space
}
}
return $output_list
}
This proc will group whitespace separated 'words' until they have no unmatched curlies, double quotes, or square brackets. Whitespace is preserved inside of matching pairs of curlies, double quotes or square brackets.
> set command {foreach {k v} [list k1 v1 k2 v2] {puts "$k $v"}}
> foreach word [command_to_list $command] {puts $word}
foreach
{k v}
[list k1 v1 k2 v2]
{puts "$k $v"}
Lets say below is something i've stored in a config variable in tcl.
#set config "configuration {
test_config {
address 1.2.3.4:https
}
}"
Using tcl cmd, either grep or awk or string cmds, how do i take out "1.2.3.4:https" into a variable.
So when i use do something like below,
#puts $output
1.2.3.4:https
I know how it can be done in simple bash though
#echo $config | grep address | awk '{print $2}'
#1.2.3.4:https
Can someone please help in tcl. I tried to explore string functions, but they are not giving my required output and I'm learning about regexp now.
You're probably looking for the regexp command, especially with the -line option. The trick here is to use \s* (or \s+) to match spaces and \S+ to match non-spaces.
if {[regexp -line {^\s*address\s+(\S+)} $config -> address]} {
puts "The address is $address"
}
If there are multiple address lines, you might instead do:
foreach {-> address} [regexp -inline -all -line {^\s*address\s+(\S+)} $config] {
puts "The address is $address"
}
I'm sure Donal's suggestion is the more efficient: here's a procedural way to do it:
foreach line [split $config \n] {
lassign [regexp -inline -all {\S+} $line] first second
if {$first eq "address"} {
set output $second
break
}
}
I have file with the below lines (file.list):
insert_buffer [get_ports { port }] BUFF1 -new_net net -new_cell cell
I'm reading the file with the below script (read.tcl):
#! /usr/local/bin/tclsh
foreach arg $argv {
set file [open $arg r]
set data [ read $file ]
foreach line [ split $data "\n" ] {
puts $line
set name [lindex $line [expr [lsearch -all $line "-new_cell"]+1]]
puts $name
}
close $file
}
while running the above script (read.tcl file.list) I get error since I have "[" in file.list and script think its a beginning of TCL command.
list element in braces followed by "]" instead of space
while executing
"lsearch -all $line "-new_cell""
("foreach" body line 5)
invoked from within
"foreach line [ split $data "\n" ] {
How can I read the file correctly and overcome the "[" symbol?
How can I read the file correctly and overcome the "[" symbol?
I don't really understand why you are doing what you are doing (processing one Tcl script by another), but you have to make sure that each line is a valid Tcl list before submitting it to lsearch.
lsearch -all [split $line] "-new_cell"
Only split will turn an arbitrary string (containing characters special to Tcl) into a valid Tcl list.
This is one of the few times in Tcl that you need to worry about what type of data you have. $line holds a string. Don't use list commands on strings because there's no guarantee that an arbitrary string is a well-formed list.
Do this:
set fields [split $line]
# don't use "-all" here: you want a single index, not a list of indices.
set idx [lsearch -exact $fields "-new_cell"]
if {$idx == -1} {
do something here if there's no -new_cell in the line
} else {
set name [lindex $fields $idx+1]
}
In order to apply a list operation on the variable, it has to be a valid list. The variable $line is not a valid list.
It is better to use regexp rather than lsearch
regexp -- {-new_cell\s+(\S+)} $x match value
puts $value
Output :
cell
when I am using the while loop to match a variable using regexp I want the matched variable to form a list by using lappend. The code is
set file_name [open filename.txt r]
set newlist [list]
while {[gets $file_name line] >= 0} {
regexp {cell \(\"(.*)\"} $line match cell_name
if {[info exists cell_name] && $cell_name != ""} {
puts "$cell_name"
lappend $newlist $cell_name
unset cell_name
}
}
foreach item $newlist {puts $item}
close $file_name
The text which it is matching is like cell ("aabbcc") where the values inside the quotes are changing. The values are getting captured by this code but it is not creating a list after appending. I need all the values as a list. Can u pls tell me where I am going wrong.
A $ too much.
Change the line
lappend $newlist $cell_name_matched
to
lappend newlist $cell_name_matched
Otherwise you find the result in ${}.
You should also check if you regexp finds something:
if {[regexp {cell \(\"(.*)\"} $line match cell_name_matched]} {
puts "$cell_name_matched"
lappend newlist $cell_name_matched
}
The unset will probably throw an error too, leave it alone and remove it.
In TCL, I have declared an array sstr with some patterns and I would like to match that patterns with the cryplist. If I found that match, I am displaying with array key and the matched list member. But the below program is not working. Hope I did some mistake in the declaration of regular expression.
#!/bin/tclsh
set cryplist [list "$:adzctg-cm20decadt/sr" "$:yyzpty-cm23febadt/sr" "dc*aed1740.0*gbp" "dc*ars1*usd" "dc*gbp10.00*/r" "d|t|lbb/den" "d|t|ordphx"]
array set sstr {
z "dc*[a-z]{3}*"
dl "d\$*[0-9]"
fd "\$:[a-z]{6}"
md "d|t|[a-z]{3}\/[a-z]{3}"
ms "d|t|[a-z]{6}"
}
foreach i $cryplist {
puts "------------- $i --------------"
foreach {n str} [array get sstr] {
puts "$n -> $str"
if { [regexp {$str} $i ] } {
puts "============= $n -> $i ================"
break
}
}
}
The problem is that you're using regexp {$str} $i, which makes the regular expression be the literal $str and not the contents of the str variable. Change to regexp -- $str $i and it should work; the -- says “no further options” (just for safety) and the unquoted $str reads from the variable for that argument (what you want).