Skip to content
VLSI Mentor

Tcl Part I · Module 5 · Strings

scan: Reading Fields Out of a Fixed Line

This is the opposite of the previous chapter. Where format takes values and produces a line, scan takes a line and produces values — using the same conversion vocabulary, so most of it you already know. The part that needs attention is what it returns, because it does not raise an error when a line does not match the pattern. It tells you how many fields it managed to read, and a line that matched only halfway leaves the rest of your variables unset while the script carries on perfectly happily.

Foundation11 min readTclPart IStringsscanParsing

Part I · Module 5 · Chapter 5.12 · scan: Reading Fields Out of a Fixed Line

1. The Opposite of format

Azvya Education Pvt. Ltd.VLSI Mentor
basic.tcl
set line "widget 42 3.5"

scan $line "%s %d %f" name count value

puts "name=$name count=$count value=$value"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
name=widget count=42 value=3.5

The conversions are the same ones from Chapter 5.11 — %s for text, %d for a whole number, %f for a real one. The difference is direction: here they say what to read, and the trailing arguments are variable names to store into.

No $ on those names, for the same reason as set and append.

2. What It Returns

This is the chapter:

Azvya Education Pvt. Ltd.VLSI Mentor
count.tcl
set line "widget 42 3.5"

set n [scan $line "%s %d %f" name count value]
puts "conversions that succeeded: $n"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
conversions that succeeded: 3

scan returns how many conversions succeeded, not whether the line was valid. Three conversions, three successes.

3. It Does Not Error on a Bad Line

Azvya Education Pvt. Ltd.VLSI Mentor
no-error.tcl
set n [scan "abc" "%d" number]
puts "returned: $n"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
returned: 0

Zero conversions, no error. The variable number was never set.

That is survivable because zero is obviously wrong. The dangerous case is in between.

4. The Partial Match

Azvya Education Pvt. Ltd.VLSI Mentor
partial.tcl
set line "oops"

set n [scan $line "%s %d %f" name count value]

puts "returned: $n"
puts "name is:  $name"
puts "count is: [info exists count]"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
returned: 1
name is:  oops
count is: 0

One conversion succeeded. name was set; count and value were not set at all.

If the script had gone straight on to use $count, it would have hit can't read "count": no such variable — which is at least an error, several lines away from the cause. And if count happened to hold a value from a previous iteration of a loop, there would be no error at all and the old value would be used as though it were new data.

5. Literal Text in the Pattern

Anything that is not a conversion must appear in the input exactly:

Azvya Education Pvt. Ltd.VLSI Mentor
literals.tcl
set date "2024-10-07"

if {[scan $date "%d-%d-%d" year month day] == 3} {
    puts "year=$year month=$month day=$day"
}
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
year=2024 month=10 day=7

The dashes in the pattern matched the dashes in the input. This is how you parse a structured field without splitting it.

Note day came back as 7, not 07 — %d produces a number, and the leading zero is gone. That is usually what you want, and it neatly sidesteps the octal problem from Chapter 3.5 §6: scan is the recommended way to read a zero-padded field precisely because it gives you a decimal number.

6. Whitespace and %s

A space in the pattern matches any amount of whitespace:

Azvya Education Pvt. Ltd.VLSI Mentor
whitespace.tcl
puts [scan "a    42" "%s %d" w n]
puts "w=$w n=$n"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
2
w=a n=42

Four spaces matched the single space in the pattern.

Be aware that %s reads up to the next whitespace, so it cannot capture a value containing spaces:

Azvya Education Pvt. Ltd.VLSI Mentor
s-stops.tcl
scan "two words here" "%s" first
puts "captured: <$first>"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
captured: <two>

For a field that may contain spaces, use character classes — %[^,] reads everything up to a comma — or use Chapter 5.13 instead.

Azvya Education Pvt. Ltd.VLSI Mentor
class.tcl
set n [scan "key=some value" "%\[^=\]=%s" k v]
puts "n=$n k=<$k>"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
n=2 k=<key>

7. When Not to Use It

scan suits lines with a predictable shape. It is the wrong tool when:

  • the fields are separated by a consistent character and you just want them all — use split, Chapter 5.13
  • the shape varies from line to line — use a regular expression, Module 13
  • you only need one value from a known position — use string range, Chapter 5.3

The sweet spot is a fixed line with typed fields, where you want the numbers to come back as numbers without converting them yourself.

8. A Complete Example

Azvya Education Pvt. Ltd.VLSI Mentor
complete.tcl
set lines {
    "widget 42 3.5"
    "gadget 7 1.25"
    "broken line"
    "doodad 19 0.5"
}

set total 0.0
set used 0
set skipped 0

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

    if {[scan $line "%s %d %f" name count value] != 3} {
        incr skipped
        continue
    }

    set total [expr {$total + $count * $value}]
    incr used
}

puts [format "%d lines used, %d skipped, total %.2f" $used $skipped $total]
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
3 lines used, 1 skipped, total 165.25

The count check is what makes the bad line survivable, and the script reports how many it skipped rather than quietly dropping it — Chapter 3.11 §4.

9. Common Mistakes

Ignoring the return value. §4. The main one.

Checking > 0 instead of the exact count. A partial match passes that test.

Putting $ on the variable names. They are names, like set and append.

Expecting %s to capture spaces. It stops at whitespace. §6.

Using it on irregular text. §7.

Assuming unset variables are empty. They are unset, which is an error to read — Chapter 3.2 §8.

10. Exercises

Exercise 1 — three fields. Parse "alpha 10 2.5" into three variables and print the count that scan returned.

Exercise 2 — the partial match. Run scan "alpha" "%s %d %f" a b c and print the return value and info exists c. Explain what a script that ignored the count would do next.

Exercise 3 — a date. Parse "07/10/2024" into day, month and year. Confirm the leading zero is gone and say why that matters.

Exercise 4 — the guard. Take Exercise 1 and add the exact-count check. Then feed it "alpha ten 2.5" and confirm it is rejected.

Exercise 5 — a field with spaces. Parse "name=My Report" into a key and a value, keeping the space in the value. Which technique did you need?

Exercise 6 — pick the tool. For each, say scan, split or string range: a comma-separated row; a fixed-width record; a line of word number number; a log line whose format changes between tools.

11. Remember

  • scan is format in reverse, with the same conversions.
  • The trailing arguments are variable names, with no $.
  • It returns how many conversions succeeded — not whether the line was valid.
  • A bad line does not raise an error. It returns a smaller number.
  • A partial match leaves later variables unset, and the script carries on.
  • Check the exact count: if {[scan ...] != 3} { ... }.
  • Literal text in the pattern must appear in the input, which is how you parse structured fields.
  • %d returns a decimal number, so it is the safe way to read a zero-padded field.
  • %s stops at whitespace. Use a character class or split for fields containing spaces.
  • Use it for predictable lines only.

One chapter remains, and it is the one that connects this whole module to the next.

Where this fits

Part of the Tcl curriculum.