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
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 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.
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.
Why can't I remove the pound sign commented line?
#!/usr/bin/tclsh
set lines [list file1.bmp { # file2.bmp} file3.bmp ]
# Now we apply the substitution to get a subst-string that
# will perform the computational parts of the conversion.
set out [regsub -all -line {^\s*#.*$} $lines {}]
puts $out
Output:
file1.bmp { # file2.bmp} file3.bmp
-UPDATE-
Expected output:
file1.bmp {} file3.bmp
{} means empty string.
In fact, it's my first step. My ultimate goal is to eliminating all commented line and all empty lines. The above question only changes all comment lines into empty lines. For example, if the input is:
set lines [list file1.bmp { # file2.bmp} {} file3.bmp ]
I want my ultimate results to be
file1.bmp file3.bmp
Note: Stackoverflow mistakenly dim everything from and after the pound (#) sign, thinking that those are comments. Yet in TCL syntax, it should not be comments.
#Tensibai:
I also want to remove empty lines, thus I match any number of spaces before '#'. (since after removing all following '#' included, it's an empty line). In fact, in my data, the comment always appears as a full line by itself. Yet the '#' sign may not appear at the 1st character => the spaces can leads a comment line.
Edit to answer after edit:
#!/usr/bin/tclsh
set lines [list file1.bmp { # file2.bmp } file3.bmp #test ]
puts $lines
# Now we apply the substitution to get a subst-string that
# will perform the computational parts of the conversion.
set out [lsearch -regexp -all -inline -not $lines {^\s*(#.*)?$}]
puts $out
Output:
file1.bmp file3.bmp
You're working on a list, the representation of a list is a simple text so you can regsub it, but it's a single line.
If you want to check elements on this list you have to use list related commands.
Here lsearch will do what you wich, checking each item to see if they match the regex, the -not tells to return the elements no matching with -all -inline
Old answer:
Why: because your regex match any pound preceded only by 0 or unlimited number of spaces. Thus it will only match comment lines and not inline comments.
Have a look to http://regex101.com to test regexes.
A working regex would be:
#!/usr/bin/tclsh
set lines [list file1.bmp { # file2.bmp} file3.bmp ]
# Now we apply the substitution to get a subst-string that
# will perform the computational parts of the conversion.
set out [regsub -all -line {^(.*?)#.*$} $lines {\1}]
puts $out
For the regex (complete details here):
^ Matches start of line
(.*?)# Matches and capture as limited number of chars as possible before the # (non greedy operator ? to limit the match)
.*$ matches any numbe of chars until end of line
And we replace with \1 which is the first capture group (and the only one in this case).
Output:
file1.bmp {
This will also remove full line comments but may leave spaces or tabs if there's some before the pound sign and so leave blank lines.