string compare ...

I've no idea why someone thought this page might be useful... RS thinks that in some page [string compare ...] was written with single brackets, which open a potential new page if somebody clicks on the blue brackets. But now that we have this page, comparing strings can be done in various ways:

 if {$name=="foo"} {...}                  ;# (1)
 if {$name eq "foo"} {...}                ;# (2)
 if {[string compare $name foo]==0} {...} ;# (3)
 if {[string equal $name foo]} {...}      ;# (4)
 if {[string match foo $name]} {...}      ;# (5)

(1) is the classic overloading of comparison operators in expr to work also on non-numeric strings, but first tries numeric, including the various number bases, so

 8 == 010
 0xF == 15 == 017

(2) is new string comparison operators from 8.4 or so

(3) used to be recommended, but is so wordy...

(4) is recommended since 8.3 or so

(5) degenerates to 'equal' if the first argument (pattern) does not contain glob meta characters.

Note that string compare is preferred over the == or != if there is a chance that the data could be interpreted as numerics.

Note that string literals must be quoted in (1) and (2).

AMG: Here's another method that lets you compare multiple strings at the same time: if {$name in {foo foo2 foo3}} {...}. In Tcl 8.5 and older, use [lsearch -exact {foo foo2 foo3} $name]. [regexp] also works: [regexp {^foo$|^foo2$|^foo3$} $str].

ASPENLOGIC: Why doesn't string compare come with the same comparison options as lsort? It seems more orthogonal to promote the same comparisons options as would be used in a sort. (I'd like to implement an lsort command which compares multiple strings from CSV data stored in a list of lists and -dictionary is critical.)

AMG: Here are the options for [lsort], along with a brief evaluation of their fitness for [string compare].

  • -ascii: This is already how [string compare] operates, all the time.
  • -dictionary: Could be useful for [string compare].
  • -integer: Use the numerical comparison operators instead (<, <=, >, >=, ==, !=).
  • -real: Use the numerical comparison operators instead.
  • -command command: Just call the command directly.
  • -increasing: Already how [string compare] works.
  • -decreasing: Simply negate the return value of [string compare].
  • -indices: Inappropriate, since there are no lists involved.
  • -index indexList: Inappropriate, since there are no lists involved.
  • -stride strideLength: Inappropriate, since there are no lists involved.
  • -nocase: [string compare] already has this option.
  • -unique: Inappropriate, since there are no lists involved.

From that list, the only potentially useful addition is -dictionary, which you ask for. However, I've only ever needed it when sorting a list, never when merely comparing two strings. If you must, here's a way to make it available:

proc string_compare_dictionary {a b} {
    dict get {1 0    {0 1} -1    {1 0} 1}\
        [lsort -indices -dictionary -unique [list $a $b]]
}

Basically this uses [lsort] to sort a two-element list, then translates the order of the returned element indices to a [string compare] return code.