Skip to content
VLSI Mentor

Tcl Part I · Module 5 · Strings

split and join: The Bridge Between Strings and Lists

These two commands connect this module to the next one. Almost every list you work with in real scripting arrives as text — a comma-separated row, a path, a line of output — and split is how it becomes a list you can index and iterate. join takes it back the other way. The mechanism is simple and there are exactly three places it surprises people, all of which come from the same root: the separator argument does not mean quite what it looks like, and the default behaviour is not the one other languages chose.

Foundation13 min readTclPart IStringsListsParsing

Part I · Module 5 · Chapter 5.13 · split and join

1. The Two Directions

Azvya Education Pvt. Ltd.VLSI Mentor
basic.tcl
set line "alpha,beta,gamma"

set fields [split $line ","]
puts "as a list: $fields"
puts "elements:  [llength $fields]"

puts "rejoined:  [join $fields " | "]"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
as a list: alpha beta gamma
elements:  3
rejoined:  alpha | beta | gamma

split turns text into a list by cutting at a separator. join turns a list back into text by putting a separator between the elements.

Two flows. Going right, a comma-separated string passes through split and becomes a three-element list. Going right on the second row, a three-element list passes through join and becomes a string with separators between the elements.Textalpha,beta,gammasplitcut at each separatorA list3 elements you can indexA list3 elementsjoinput a separator betweenTextalpha | beta | gamma12
Figure 1 — the bridge between text and lists. split cuts a string at its separators and produces a list you can index, count and iterate. join does the reverse, putting a separator between elements to produce text again. Almost all real data enters a script as text and leaves it the same way, so this pair sits on the boundary of nearly every script you will write.

2. Why This Chapter Matters

Module 6 teaches lists — indexing them, sorting them, searching them. Almost none of the lists you work with will be written out by hand in your source. They will arrive as text and come through split.

So this is the hinge. Getting it right means the next module's commands operate on the data you think they do.

3. An Empty Separator Splits Into Characters

Azvya Education Pvt. Ltd.VLSI Mentor
empty-sep.tcl
puts [split "abc" ""]
puts [llength [split "hello" ""]]
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
a b c
5

The empty string as a separator means "between every character". That is a genuine and occasionally useful feature — it is how you get a list of characters — but it catches people who pass an empty variable by accident:

Azvya Education Pvt. Ltd.VLSI Mentor
accident.tcl
set sep ""
puts [split "a,b,c" $sep]
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
a , b , c

Seven elements, including the commas. If a separator comes from a variable, check it is not empty.

4. A Multi-Character Separator Is a Set

Azvya Education Pvt. Ltd.VLSI Mentor
separator-set.tcl
puts [split "a,b;c" ",;"]
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
a b c

",;" does not mean "split on the two-character sequence ,;". It means "split at a comma or a semicolon".

This is the same shape of trap as the second argument to string trim — Chapter 5.8 §4. In both commands, a string of characters means any one of these, not this exact sequence.

So you cannot split on ", " — comma-space — the way you might expect:

Azvya Education Pvt. Ltd.VLSI Mentor
not-a-sequence.tcl
puts [split "a, b, c" ", "]
puts [llength [split "a, b, c" ", "]]
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
a {} b {} c
5

Five elements, with empty ones where the comma and the space both counted as separators.

The fix is to split on the comma alone and trim each piece — which needs Module 9's loops, or:

Azvya Education Pvt. Ltd.VLSI Mentor
split-then-trim.tcl
set line "a, b, c"
puts [split [string map {", " ","} $line] ","]
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
a b c

Normalise the separator with string map first, then split on a single character. That is Chapter 5.9 doing exactly the job it is good at.

5. The Default Does Not Collapse Whitespace

The biggest surprise in this module.

With no separator argument, split cuts on whitespace. You would reasonably expect consecutive spaces to be treated as one. They are not:

Azvya Education Pvt. Ltd.VLSI Mentor
default-split.tcl
set s "a b  c"

puts "split:   [split $s]"
puts "elements: [llength [split $s]]"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
split:   a b {} c
elements: 4

Four elements, and the third is empty. The two spaces between b and c produced an empty element between them.

If you have written Python, this is the opposite of what "a b c".split() does.

Now compare with how Tcl reads the same text as a list:

Azvya Education Pvt. Ltd.VLSI Mentor
as-a-list.tcl
set s "a b  c"

puts "llength:          [llength $s]"
puts "llength of split: [llength [split $s]]"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
llength:          3
llength of split: 4

Three versus four, from the same text. List parsing collapses runs of whitespace; split does not.

6. Empty Elements Are Data

Adjacent separators produce an empty element, and that is correct rather than a bug:

Azvya Education Pvt. Ltd.VLSI Mentor
empty-elements.tcl
set row "alpha,,gamma"

set fields [split $row ","]
puts "fields:   $fields"
puts "count:    [llength $fields]"
puts "second:   <[lindex $fields 1]>"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
fields:   alpha {} gamma
count:    3
second:   <>

Three fields, the middle one empty. In a CSV row that is exactly right — the column exists and has no value, which is different from the column being absent.

The braces in the printed output are how Tcl shows an empty element in a list. They are not characters in the data.

And it round-trips:

Azvya Education Pvt. Ltd.VLSI Mentor
round-trip.tcl
set row "alpha,,gamma"
puts [join [split $row ","] ","]
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
alpha,,gamma

7. join Is Simpler

Azvya Education Pvt. Ltd.VLSI Mentor
join.tcl
set items {red green blue}

puts [join $items ", "]
puts [join $items "\n"]
puts [join $items]
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
red, green, blue
red
green
blue
red green blue

The separator can be any text, including a newline — which is the neat way to turn a list into lines of output.

With no separator argument, join uses a single space.

Note the asymmetry: join takes a separator string used literally, while split takes a set of separator characters. They are not exact inverses, which is §4's point from the other direction.

8. A Complete Example

Parsing a configuration line:

Azvya Education Pvt. Ltd.VLSI Mentor
config.tcl
set lines {
    "timeout = 30"
    "retries = 3"
    "mode = fast"
}

foreach line $lines {
    set line [string trim $line]
    if {$line eq ""} { continue }

    set i [string first "=" $line]
    if {$i < 0} { continue }

    set key   [string trim [string range $line 0 $i-1]]
    set value [string trim [string range $line $i+1 end]]

    puts [format "%-10s = %s" $key $value]
}
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
timeout    = 30
retries    = 3
mode       = fast

Note what is not used here: split on "=". Because a value might itself contain an equals sign, finding the first one — Chapter 5.4 §5 — is safer.

Where split is right is when every separator is a real boundary:

Azvya Education Pvt. Ltd.VLSI Mentor
csv.tcl
set row "clk,1,input"

lassign [split $row ","] name width direction
puts "name=$name width=$width direction=$direction"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
name=clk width=1 direction=input

lassign unpacks a list into variables in one line; Module 6 covers it.

9. Common Mistakes

Expecting bare split to collapse whitespace. §5. The biggest one.

Treating a multi-character separator as a sequence. §4. It is a set.

Passing an empty separator by accident. §3. You get characters.

Treating an empty element as an error. §6. In delimited data it is a real empty field.

Using split when the value may contain the separator. §8. Find the first one instead.

Expecting split and join to be exact inverses. §7.

10. Exercises

Exercise 1 — both directions. Split "one:two:three" on the colon, print the element count, then rejoin with " -> ".

Exercise 2 — the whitespace surprise. Predict the element count of split "x y z" before running it. Then print llength "x y z" and explain why the two differ.

Exercise 3 — a separator set. Predict the result of split "a-b_c" "-_" and of split "a-_b" "-_". Run both.

Exercise 4 — empty fields. Split the CSV row ",alpha,,beta," and print the count and each element in angle brackets. How many are empty, and where?

Exercise 5 — comma-space. Turn "red, green, blue" into a clean three-element list, using the string map approach from §4. Confirm no element has a leading space.

Exercise 6 — characters. Produce a list of the individual characters of "Tcl", then rejoin them with dashes.

Exercise 7 — pick the tool. For each, say split or string first: a CSV row; a key=value line where the value is a URL; a path separated by slashes; a line of name: description text.

11. What You Can Now Do

That closes Module 5. Across thirteen chapters you have the whole of Tcl's ordinary text handling:

  • the string command's shape, and how to discover its subcommands
  • measuring, indexing and slicing
  • finding literal text, and handling the -1
  • matching shapes with glob patterns
  • comparing, with and without case
  • normalising case and whitespace at the boundary
  • replacing by position and by content
  • building text up with append
  • formatting it for a person to read, and scanning it back
  • and converting between text and lists

Not one regular expression has appeared. That is deliberate: the overwhelming majority of real text handling is covered by what you now know, and Module 13 opens by saying so. When you reach it, you will be able to tell the cases that genuinely need it from the ones where a glob or a string map is clearer.

Module 6 is Lists, which is where the output of split goes next — indexing, searching, sorting, and the list commands that make the data you have just parsed useful.

12. Remember

  • split makes a list from text; join makes text from a list. This is the hinge into Module 6.
  • An empty separator splits into individual characters.
  • A multi-character separator is a SET — any one of those characters — not a sequence. Same trap as string trim.
  • The default splits on whitespace and does NOT collapse runs of it. split "a b c" gives four elements.
  • Reading the same text as a list gives three, because list parsing does collapse whitespace.
  • Adjacent separators produce an empty element, which in delimited data is a real empty field.
  • join takes a literal separator string, so the two are not exact inverses.
  • Use string first instead when the value may contain the separator.
  • Normalise with string map before splitting when the separator is more than one character.

Where this fits

Part of the Tcl curriculum.