I have a lsearch issue.
here is my code.
set aa 11
lappend aa a\[1\]
lsearch $aa a\[1\]
why doesn't it work?
Try:
lsearch -exact $aa a\[1\]
By default lsearch uses glob-style matching. The backslashes prevent [1] being treated as a command substitution, but then lsearch sees the item to find as a[1] which as a glob pattern just means "a" followed by "1". So you need the -exact flag to have the item to find just treated as literal text.
Related
I am new to TCL word. I have a list which js numeric and when I use lsearch for numeric it is not print properly. Could you please help me what's wrong in my command
set a {12,121,124,21,212}
lsearch -integer $a 12
Expected output : 12
Actual Output : 12,121, 124, 212
You've got a list that is separated by commas, whereas Tcl lists (the kind that lsearch can search and lsort can sort) are separated by spaces. The split command can do the conversion for you:
set a {12,121,124,21,212}
set theList [split $a ","]
lsearch -integer $theList 12
The result of the search is 0, which is the index of the first item in the list (Tcl uses zero-indexing, like a lot of programming languages).
To get the actual value found (no so useful in this case, but definitely more useful in more complex ones) you'd provide the -inline option.
lsearch -inline -integer $theList 12
I tried lsearch -all $list_ 0,a1[4],*
a1[4] is stored in a variable
SO basically need
set var "a1[4]"
lsearch -all $list_ 0,$var,*
By default lsearch uses glob patterns (as described by the documentation for string match — it's the exact same matching engine being used). That's good because it means that * is a wildcard, but awkward because it means that [ is also special (it starts a character set match). You need some simple escaping, and to keep that sane you should put your whole pattern in {braces} so we don't need to fight with Tcl over what the meanings of bracket and backslash are:
lsearch -all $list_ {0,a1\[4\],*}
You don't need braces; you could write this instead:
lsearch -all $list_ 0,a1\\\[4\\\],*
But that's ugly! And difficult to maintain (trust me on that). So use braces, OK?
In the case where you're pulling the subpattern from a variable, things get more complicated. The fix is to use string map (or regsub) to condition the pattern piece.
# Split into three lines for clarity; qvar = “quoted var”
set ADD_BACKSLASHES {[ {\[} ] {\]}}
set qvar [string map $ADD_BACKSLASHES $var]
lsearch -all $list_ 0,$qvar,*
I'm trying to use lsearch using glob test on sub-pattern, but it's not working:
set haystack {foo bar baz}
lsearch -inline -all $haystack baz; # finds baz
lsearch -inline -all $haystack *o; # finds foo
lsearch -inline -all $haystack {{baz,*o}}; # finds nothing
Sub-pattern works using the actual glob command (the files being the haystack in that case), so it appears to be an issue with lsearch.
glob {{b*,c*}}; # finds all files starting with either b or c
Is there a way to make it work?
No, the pattern that you use with lsearch is not meant to be able to match what you are trying to make it match. The manual specifies that it uses:
the same rules as the string match command.
And there is no mention of the style { ... }. If you look at the manual for glob however, you will see the { ... } syntax mentioned:
{a,b,...}
Matches any of the sub-patterns a, b, etc.
You can however use -regexp if you know the syntax. For your example, you could use:
set haystack {foo bar baz}
lsearch -inline -all -regexp $haystack {baz|.*o}; # finds foo baz
I am getting an error message in this regex when line contains unbalanced braces.
set line "a b { c{}"
set lst [regexp -all -inline {^(\s*(\S*)\s*)*(\{(.*)\})?(\s*(\S*)\s*)*$} $line]
set lst [lindex $lst 0]
set firstelement [lindex $lst 0]
How to avoid such cases and treat unbalanced braces as a word?
When you have a string from an arbitrary source (like a user) there's no guarantee at all that it is a well-formed list. Now regexp -inline returns a list of what it matched, but the elements of that list are strings (unless you use the -indices option, of course) and that means that you can't safely use lindex on them to pick out the pieces.
The safe way to get the first “word”, assuming you define “word” to be “sequence of non-whitespace characters” (the usual user definition), is to do this:
set firstWord [lindex [regexp -all -inline {\S+} $item] 0]
It's a bit ugly, but it's totally safe. (In fact, for the first word only, use regexp -inline {\S+} $item on its own, but that won't let you get later words.)
Using split to break a string into words is also possible, but that strongly assumes that the word separator is a single (whitespace-by-default) character and does something that you might not expect if you have multi-whitespace separators, or leading and trailing whitespace. Frankly, it's more useful for dividing up non-whitespace separated strings (e.g., a file into lines, an /etc/passwd record into fields) or for turning a string into the list of its characters (with an empty second argument).
The regexp command returns a list. You then take the first element of the list. But in the final line you then treat that element as a list - but it is not guaranteed to be so - hence the actual string content matters. Instead, if you want to deal with this item as a list you need to use split and convert it into words:
% split "a b {" " "
a b \{
In your case:
set lst [lindex $lst 0]
set firstelement [lindex [split $lst " "] 0]
You may also want to look into subst. It looks like you are trying to read poorly specified tcl lists as input and doing some parsing to get them as a proper tcl list. In which case, subst -nocommands [lindex $lst 0] might be more helpful to you. For example:
% lindex [subst -nocommands [lindex $lst 0]] 2
c{}
Note that this is the content of the braced part of $line.
I have a list containing one member, that member is the string <cmd_stichstudy1>XXDDR0_MA[12]. When I search for that string in the list (using lsearch) I get that the list doesn't contain it. I even get it when I search for the member of the list:
tcl> set nets_names
{<cmd_stichstudy1>XXDDR0_MA[12]}
tcl> lsearch $nets_names [lindex $nets_names 0]
-1
Why does this happen?
If you use -exact it will work the way you want.
% set nets_names {<cmd_stichstudy1>XXDDR0_MA[12]}
<cmd_stichstudy1>XXDDR0_MA[12]
% lsearch -exact $nets_names [lindex $nets_names 0]
0
%
lsearch has an unfortunate property of using glob-style matching by default.
To cite the manual:
If all matching style options are omitted, the default matching style is -glob.
So always pass -exact to lsearch unless you really want -glob.