When do you use Scanner, and how does it compare with Regex and split?
Predict first
What does this print?
let sc = Scanner(string: "12 apples")
print(sc.scanInt() as Any, sc.scanCharacters(from: .letters) as Any)
- Optional(12) nil
- Optional(12) Optional("apples")
- nil nil
Predict first
What does this print?
if let match = "12 apples".firstMatch(of: /(\d+) (\w+)/) {
print(match.output.2)
}
- 12
- apples
- 12 apples
Mental model. A Scanner is a finger sliding along a line of text, picking up one item at a time. Regex is a template laid over the whole line.
Scanner is a stateful cursor that walks a string left to right, pulling out typed pieces: scanInt(), scanDouble(), scanCharacters(from:), scanUpToString(_:). Each call returns an optional and advances only on success. By default it skips leading whitespace and newlines (charactersToBeSkipped), which is convenient and sometimes surprising. isAtEnd and currentIndex tell you where you are.
Pick the tool by the shape of the text. split and components suit simple delimiters. Regex (Swift 5.7 regex literals and RegexBuilder) suits patterns and captures. Scanner suits sequential tokenising of formats like "3.5,4", and NSDataDetector finds links, dates and phone numbers in free text. For a single whole-string number, Int(_:) is enough and stricter: it rejects spaces and trailing text.
Each call advances the cursor, and by default the scanner skips the space before apples.
A regex literal produces typed captures: output.0 is the whole match, .1 the digits, .2 the word.
Common traps
- Ignoring the optional. A failed scan returns
niland does not move, so a loop that retries can spin forever. - Parsing decimals with a locale mismatch. A scanner with
localeset reads3,5as a decimal in some locales.
They might follow up with
- How do you change what is skipped? Set
charactersToBeSkippedto a different set, ornilto skip nothing. - When is
Int("12 apples")right? Never for that input: it returnsnil. Scan the number, or use a regex.
Related questions
- 2.8.4 How do you format numbers, currency and percentages correctly?
← Why do ranges break when you move between String, AttributedString… How do you format numbers, currency and percentages correctly? →