In the file I have something like this:
name(0) = 123
name(1) = 456
name(2) = 789
I want to write match string to array.
for { set i 0 } { $i < 3 } { incr i } {
regexp {name\($i\) =\s+(.*)} $line full($i) name($i)
}
I don't know why regexp don't recognizes $i counter.
If I write:
regexp {name\(0\) =\s+(.*)} $line full($i) name($i)
working but only for first counter.
Braces in Tcl quote the string literally, so no variable substitution is done. If you want variable substitution, use double quotes. Since you are quoting a regular expression, the backslashes will need to be escaped.
Convert:
{name\($i\) =\s+(.*)}
To:
"name\\($i\\) =\\s+(.*)"
Or as DKF has suggested. This makes it easier to see the regexp without all the backslashes
set pattern [format {name\(%d\) =\s+(.*)} $i]
regexp $pattern $line full($i) name($i)
References: Tcl syntax, regex syntax, format
Related
I want to split a string into separate words which which are enclosed in single quotes like below:
For example:
set str {'Name' 'Karna Mayer' ''}
I want to split this into 3 separate words. How can this be performed using Tcl.
For this sort of task, I'd use regexp -all -inline and lmap (to drop the unwanted bits from the results of that).
set input "'Name' 'Karna Mayer' ''"
set output [lmap {- bit} [regexp -all -inline {'([^'']*)'} $input] {set bit}]
The good thing about this is that if you have a way of escaping a single quote in that, you can use a more complex regular expression and match that too.
set output [lmap {- bit} [regexp -all -inline {'((?:\\.|[^''])*)'} $input] {
string map {\\ {}} $bit
}]
You can use string map to convert the single quotes to double quotes and escape existing quotes
set str [string map {{"} {\"} ' {"}} $str]
# "name" "Karna Mayer" ""
you can then use list and argument expansion to convert it to a list
set l [list {*}$str]
# Name {Karna Mayer} {}
full program
set str {'Name' 'Karna Mayer' ''}
set str [string map {{"} {\"} ' {"}} $str]
set l [list {*}$str]
If you use single quote as a separator, then you'll take every second element:
% set input "'Name' 'Karna Mayer' ''"
'Name' 'Karna Mayer' ''
% split $input {'}
{} Name { } {Karna Mayer} { } {} {}
We see: the empty string before the first quote; the first field; the space between the 1st and 2nd; the 2nd field; the next space; the (empty) 3rd field; and then the empty string after the last quote. We want to ignore this last element.
% set fields [lmap {_ field} [lrange [split $input {'}] 0 end-1] {set field}]
Name {Karna Mayer} {}
No thanks to the Tcl syntax highlighter.
Hi I am new to tcl and want to assign "\n" to a variable and use that variable in regsub to replace that string.
It should be like :
set a "\n\[\"this is my code\"\]"
puts $a
I was expecting this will give
\n\[\"this is my code\"\], then I could use this $a in regsub {$a} $str "replace" sub_str.
This regsub could search $a inside $str and replace the matching one with replace and strore it in sub_str.
However, it gave me [this is my code]
Is there a way I could get the 1st format as \n\[\"this is my code\"\] so I could use that to do the string regsub?
Thanks!
Use braces instead of quotes to prevent evaluation of the backslash escapes:
set a {\n\[\"this is my code\"\]}
puts $a
prints
\n\[\"this is my code\"\]
I have a string abc.def.ghi.j and I want to remove abc. from that, so that I have def.ghi.j.
1) What would be the best approach to remove such a prefix which has a specific pattern?
2) Since in this case, abc is coincidentally the prefix, that probably makes things easier. What if we wanted abc.ghi.j as the output?
I tried it with the split method like this
set name abc.def.ghi.j
set splitVar [split $name {{abc.}} ]
The problem is that it splits across each of a, b, c and . seperately instead of as a whole.
Well, there's a few ways, but the main ones are using string replace, regsub, string map, or split-lreplace-join.
We probably ought to be a bit careful because we must first check if the prefix really is a prefix. Fortunately, string equal has a -length operation that makes that easy:
if {[string equal -length [string length $prefix] $prefix $string]} {
# Do the replacement
}
Personally, I'd probably use regsub but then I'm happy with using RE engine tricks.
Using string replace
set string [string replace $string 0 [string length $prefix]-1]
# Older versions require this instead:
# set string [string replace $string 0 [expr {[string length $prefix]-1}]]
Using regsub
# ***= is magical and says "rest of RE is simple plain text, no escapes"
regsub ***=$prefix $string "" string
Using string map
# Requires cunning to anchor to the front; \uffff is unlikely in any real string
set string [string map [list \uffff$prefix ""] \uffff$string]
Using split…join
This is about what you were trying to do. It depends on the . being a sort of separator.
set string [join [lrange [split $string "."] 1 end] "."]
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).
I was using the command 'string trimright' to trim my string but I found that this command trims more than required.
My expression is "dssss.dcsss" If I use string trim command to trim the last few characters ".dcsss", it trims the entire string. How can I deal with this?
Command:
set a [string trimright "dcssss.dcsss" ".dcsss"]
puts $a
Intended output:
dcsss
Actual output
""
The string trimright command treats its (optional) last argument as a set of characters to remove (and so .dcsss is the same as sdc. to it), just like string trim and string trimleft do; indeed, string trim is just like using both string trimright and string trimleft in succession. This makes it unsuitable for what you are trying to do; to remove a suffix if it is present, you can use several techniques:
# It looks like we're stripping a filename extension...
puts [file rootname "dcssss.dcsss"]
# Can use a regular expression if we're careful...
puts [regsub {\.dcsss$} "dcssss.dcsss" {}]
# Do everything by hand...
set str "dcssss.dcsss"
if {[string match "*.dcsss" $str]} {
set str [string range $str 0 end-6]
}
puts $str
If what you're doing really is filename manipulation, like it looks like, do use the first of these options. The file command has some really useful commands for working with filenames in a cross-platform manner in it.