Skip to content
VLSI Mentor

Tcl Part I · Module 5 · Strings

Replacing and Mapping: string replace and string map

Two commands change text, and they answer different questions. One takes positions and swaps out a span, which makes it the writing counterpart to the range reading you saw earlier. The other takes pairs of old and new text and applies all of them in a single pass, which makes it both fast and unusually predictable — predictable enough that it can swap two values in one call, something a sequence of individual replacements cannot do. For literal substitutions it is also the tool to reach for long before a regular expression.

Foundation12 min readTclPart IStringsReplacementMapping

Part I · Module 5 · Chapter 5.9 · Replacing and Mapping

1. Two Different Questions

  • string replace — "change the characters at these positions".
  • string map — "change this text wherever it appears".

Positions versus content. Picking the wrong one is the main way to make this harder than it is.

2. string replace Works on Positions

Azvya Education Pvt. Ltd.VLSI Mentor
replace.tcl
set line "0123456789"

puts "replace 0 3 with XX  -> <[string replace $line 0 3 "XX"]>"
puts "replace 0 3 (delete) -> <[string replace $line 0 3]>"
puts "replace end-1 end    -> <[string replace $line end-1 end "!"]>"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
replace 0 3 with XX  -> <XX456789>
replace 0 3 (delete) -> <456789>
replace end-1 end    -> <01234567!>

Three things to notice.

The positions follow Chapter 5.3 exactly — inclusive on both ends, and end and end-N work.

Omit the replacement and the span is deleted. That is the normal way to cut characters out.

The replacement need not be the same length. Four characters became two.

Like everything else in Chapter 5.1 §7, it returns a new string and leaves the original alone.

3. string map Works on Content

Azvya Education Pvt. Ltd.VLSI Mentor
map.tcl
set label "my report/draft"

puts "<[string map {" " "_" "/" "-"} $label]>"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
<my_report-draft>

The argument is a list of pairs: find this, replace with this, repeated. Here spaces become underscores and the slash becomes a dash, in one call.

That alone is useful — one command instead of a chain. But the property that matters is how it does it.

4. One Pass, No Cascading

string map scans the text once, left to right. A replacement it has already made is never looked at again:

Azvya Education Pvt. Ltd.VLSI Mentor
no-cascade.tcl
puts [string map {a b  b c} "aaa"]

Predict that. The pairs say "a becomes b" and "b becomes c". If the replacements cascaded, every a would become b and then c.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
bbb

bbb, not ccc. Each a was replaced by b, and the scan moved past it.

That is what makes a genuine swap possible:

Azvya Education Pvt. Ltd.VLSI Mentor
swap.tcl
puts [string map {cat dog  dog cat} "cat dog"]
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
dog cat

The two values exchanged places in one call.

Try that with two sequential replacements and it cannot work — the first turns every cat into dog, and the second then turns all the dogs, including the new ones, back into cats. You would need a temporary placeholder. string map needs nothing.

5. Order Within the Pairs Does Matter

One thing you do have to think about. At each position, the first matching pair in the list wins:

Azvya Education Pvt. Ltd.VLSI Mentor
order.tcl
puts [string map {ab X  abc Y} "abc"]
puts [string map {abc Y  ab X} "abc"]
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
Xc
Y

Same input, same pairs, different order, different answer.

In the first, ab was listed first and matched at position 0, leaving c behind. In the second, abc was listed first and matched the whole thing.

Put longer patterns before shorter ones when one is a prefix of another.

6. Ignoring Case

Azvya Education Pvt. Ltd.VLSI Mentor
nocase.tcl
puts [string map -nocase {ERROR ok} "error and Error"]
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
ok and ok

The pattern matches regardless of case; the replacement is used exactly as written.

7. Where You Will Use These

Making a safe filename:

Azvya Education Pvt. Ltd.VLSI Mentor
safe-name.tcl
set title "Q3 Report: Draft/Final"

puts [string map {" " "_"  ":" ""  "/" "-"} $title]
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
Q3_Report_Draft-Final

Note the empty replacement — that is how you delete a character.

Escaping for output:

Azvya Education Pvt. Ltd.VLSI Mentor
escaping.tcl
set text {a "quoted" value}

puts [string map {"\"" "\\\""} $text]
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
a \"quoted\" value

Cutting a prefix by position:

Azvya Education Pvt. Ltd.VLSI Mentor
prefix.tcl
set line "INFO: starting run"

puts [string replace $line 0 5 ""]
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
starting run

Though when the prefix length is not fixed, finding it first — Chapter 5.4 — is safer than counting characters.

8. Which to Reach For

You wantUse
change a span you know the position ofstring replace
delete a spanstring replace with no replacement
change all occurrences of some textstring map
apply several substitutions at oncestring map
swap two valuesstring map
remove characters from the ends onlystring trim
change something matching a patterna regular expression, Module 13

The last row is the boundary. string map handles literal text. The moment you need "any digit" or "one or more spaces", you need Module 13 — and that module opens by telling you to come back here when the text is literal.

9. Common Mistakes

Expecting replacements to cascade. §4. They do not, and that is the feature.

Listing a short pattern before a longer one that starts with it. §5.

Using string replace with positions that came from a search without checking them. Chapter 5.4 §4.

Reaching for a regular expression for literal substitutions. string map is faster, shorter and has nothing to escape.

Forgetting the pairs are a list. An odd number of elements is an error.

Expecting it to modify in place. It returns a new string.

10. Exercises

Exercise 1 — positions. From "abcdefgh", produce abXXfgh, abfgh, and abcdefg! using string replace three times.

Exercise 2 — predict the pass. Before running, say what each gives:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
string map {x y  y z} "xy"
string map {1 2  2 3  3 4} "123"
string map {aa b} "aaaa"

Exercise 3 — the swap. Exchange on and off in the text "led on, fan off, pump on" with one call. Then try doing it with two sequential string map calls and explain what goes wrong.

Exercise 4 — order. Write a map that turns "dog" into "D" and "do" into "X". Get it wrong first by listing do before dog, then fix it.

Exercise 5 — a safe filename. Turn "Run 7: results (final)/v2" into something with no spaces, colons, brackets or slashes, using one string map.

Exercise 6 — pick the command. For each, say replace or map: removing the first four characters; turning every tab into four spaces; blanking out characters 10 to 15; replacing every , with ;.

11. Remember

  • string replace works on positions, using the same index rules as string range, with both ends inclusive.
  • Omit the replacement to delete a span. The replacement need not be the same length.
  • string map works on content, taking a list of find-and-replace pairs.
  • It makes one left-to-right pass and never revisits what it has already replaced.
  • That is what lets it swap two values in a single call.
  • Within the pairs, the first match at a position wins — list longer patterns first.
  • -nocase matches regardless of case.
  • An empty replacement deletes.
  • Use it for literal text; use a regular expression only when you need a pattern.

Next: building a string up a piece at a time.

Where this fits

Part of the Tcl curriculum.