set pattern {\Q[9]_i_1_n_0}
string first $pattern $pattern
# => 0
Matching with string first
compares the text content of both strings without assigning any special meaning to characters. A result of 0 means that a match was found in position 0 (if there is no match, you get -1). string first
won't tell you if you've found an exact match: for that you need to ascertain that the result is 0 and the length of the strings is the same.
Matching by "glob-style" / "string match" or by regular expression needs to consider characters that are special to those matching languages. For example, \
, *
, ?
, [
, ]
are special in glob-style matching, and \
, .
, *
, +
, ?
, {
, }
, (
, )
, ^
, $
are special in regular expression matching. "Special" in this context means that e.g. \
does not mean "backslash" but (in both cases) "escape", i.e. a character that takes away the "specialness" of another character. This means that for instance \\
does mean backslash, and \*
does mean asterisk.
Since the pattern you are using contains both \
, [
, and ]
, they need to be escaped before the pattern can be used for glob-style or regex matching. (Actually, by a syntactic quirk, a ]
that closes an escaped [
doesn't need to be escaped.)
One of the easiest ways to escape these characters is by using a string translation operation performed by the string map
command. One would think that this would do the trick:
string map {\ \\ [ \[} $pattern ;# error! this code won't work!
but that won't work since backslashes are still special in the string map
command. We need to exactly double the number of backslashes in the map:
string map {\\ \\\\ [ \\[} $pattern
and now we can try to use glob-style / regex matching:
string match [string map {\\ \\\\ [ \\[} $pattern] $pattern
# => 1
regexp [string map {\\ \\\\ [ \\[} $pattern] $pattern
# => 1
The result of 1 means boolean truth: a match was found. Note that the results will differ if there is a prefix and/or suffix:
string match [string map {\\ \\\\ [ \\[} $pattern] abc${pattern}def
# => 0
regexp [string map {\\ \\\\ [ \\[} $pattern] abc${pattern}def
# => 1
This is because the string match is implicitly anchored at the ends of the pattern, while the regex needs to be explicitly anchored or it will ignore preceding or succeding text.
Matching in a list is similar. lsearch -exact
works like string first
except that it will only accept exactly equal strings. lsearch -regexp
and lsearch -glob
work like regex and glob-style matching, respectively.
set list [concat abc $pattern def]
# => abc \Q[9]_i_1_n_0 def
lsearch -exact $list [join $pattern]
# => 1
lsearch -regexp $list [string map {\\ \\\\ [ \\[} [join $pattern]]
# => 1
lsearch -glob $list [string map {\\ \\\\ [ \\[} [join $pattern]]
# => 1
The result of 1 here means that the second element in the list (index 1) matched the pattern.
(The use of concat
and join
is a bit of low-level trickery to avoid having the braces in the string representation get in the way.)
Documentation: concat, join, lsearch, Syntax of Tcl regular expressions, regexp, string