string map

Synopsis

string map ?-nocase? charMap string

Replaces characters in string based on the key-value pairs in charMap. charMap is a list of key value key value ... as in the form returned by array get. Each instance of a key in the string will be replaced with its corresponding value. If -nocase is specified, then matching is done without regard to case differences. Both key and value may be multiple characters. Replacement is done in an ordered manner, so the key appearing first in the list will be checked first, and so on. string is only iterated over once, so earlier key replacements will have no effect for later key matches. For example,

string map {abc 1 ab 2 a 3 1 0} "1abcaababcabababc"

will return the string 01321221.

[string map] is often an alternative to Regular expressions, and is sometimes more convenient.

See Also

string
regsub
ycl string template
Cut down the verbosity of string map by using the same name to obtain a value from a local variable and to map that value into the string, providing default delimiters, and by automatically quoting values with list.

History

"string map ..." was introduced as one of the Changes in Tcl/Tk 8.1.1.

Byte-compiles since 8.4

Examples

% string map {abc 1 ab 2 a 3 1 0} "1abcaababcabababc"
01321221

[string map] loses the power of regular expressions when searching for substrings, but sometimes regular expressions are overkill.


Here's an example from jenglish that lvirden thought was pretty neat:

string map -nocase {
  "&lt;"      "<"
  "&gt;"      ">"
  "&le;"      "<="
  "&ge;"      ">="
} $whatever

rpremuz 2009-01-08: An example for using the string map command can be seen in the text_replacer.tcl script.

Caveats

When using [string map] to generate Tcl code, it's a good idea to use fully-delimited placeholders, to avoid matching, eg., %TOKEN in addition to %TO.

medranocalvo 2017-02-28: I like using %{name}:

string map [list %{varname} $thevarname] {
   set %{varname} x;
}

Note that %{varname} is substituted textually; will misbehave if it contains e.g. whitespace or semicolons. The following is more robust, albeit ugly:

string map [list %{varname} $thevarname] {
   set {%{varname}} x;
}

Regex Map

IL 8/19/2006 How about a regex_map? In a language where we already have switch by regex, I think we can take this to the next level :). It's so trivial to do, but when included in the api itself, makes developers go ga-ga. then they get to say stuff like "out of the box" a lot.

proc regex_map { str args } {

    if { [llength $args] % 2 == 1} {
        set msg "wrong \# args: should be "
        append msg "regex value ?regex value?...\""
        return -code error $msg
    }
    
    foreach {regex value} $args {
        regsub -all $regex $str $value str
    }
    
    return $str
}
 % regex_map "phil is a cool guy" {co+[^ ]} sweet {[pP]hil} Ivan
 Ivan is a sweet guy

DKF: Interesting, but difficult to make work correctly when there are overlapping patterns. Not impossible though; I guess you could make a prototype that builds a single RE that searches for each of the replacements at the same time, and then combine that with the -start and -indices options to regexp to make the matching useful, and then do that in a loop and etc. Tricky to get right (there are a lot of awkward corners, like subexpressions), but once there is a Tcl version (maybe in tcllib?) we can think about the design of the C version and (after that, possibly, if enough people want it) the design of something for the core.

KPV 2017-08-10 : I've put up a solution on the string mapx page.

Discussion

See Counting characters in a string on how string map is the best performer (again to RS's surprise...) - because it gets byte-compiled since 8.4.


ak - 2017-08-14 17:59:32

I wonder if the string map internals could benefit from using https://en.wikipedia.org/wiki/Aho%E2%80%93Corasick_algorithm%|%Aho-Corasick%|% . AC exactly matches use case for the detection part of string map AFAICT. Might even be possible to compile the keys of the incoming map into a save-able int-rep.