Splitting a string into pieces
To cut a string into parts at a separator, call split(separator:). It returns an array of the pieces between the separators, and the separators themselves are left out. No import is needed.
let sentence = "hello world foo"
let words = sentence.split(separator: " ")
print(words)
print(words.count)
let csv = "a,b,c"
print(csv.split(separator: ","))
["hello", "world", "foo"]
3
["a", "b", "c"]
You can loop over the result like any array:
for word in words {
print(word)
}
hello
world
foo
The pieces are Substring values
The array's elements are Substring values, not String. They print like strings and have most of the same methods, such as count and uppercased(). They are views into the original string, so when you need a real String, for example to store it or pass it to a function that takes one, convert with String(...):
let words = "hello world foo".split(separator: " ")
let first: String = String(words[0])
let all = words.map { String($0) }
print(first)
print(all)
hello
["hello", "world", "foo"]
map { String($0) } converts every element at once and gives a [String].
Empty pieces
By default, empty pieces are dropped. Two separators in a row, or a separator at the start or end, don't produce empty strings:
print("a,,b,".split(separator: ","))
print("a,,b,".split(separator: ",", omittingEmptySubsequences: false))
print("".split(separator: " ").count)
["a", "b"]
["a", "", "b", ""]
0
Pass omittingEmptySubsequences: false when the empty fields matter, as in a table row where a column can be blank. The empty string splits into an empty array.
More control
maxSplitslimits the number of cuts. The rest of the string stays in the last piece:"a,b,c,d".split(separator: ",", maxSplits: 1)gives["a", "b,c,d"].split(whereSeparator:)takes a closure, so several characters can act as separators:"a b\tc".split(whereSeparator: { $0 == " " || $0 == "\t" })gives["a", "b", "c"].- The separator may also be a longer string, such as
", ":"one, two".split(separator: ", ")gives["one", "two"].
Splitting numbers out of text
A common use is reading values from a line of text. Split the line, then convert each piece with the Int initializer, which returns an optional because a piece may not be a number. compactMap keeps only the pieces that converted successfully:
let line = "3 4 5"
let numbers = line.split(separator: " ").map { Int($0)! }
print(numbers, numbers.reduce(0, +))
let mixed = "3 x 5".split(separator: " ").compactMap { Int($0) }
print(mixed)
[3, 4, 5] 12
[3, 5]
The ! in the first line crashes if any piece isn't a number, so it suits input you trust. For input you don't control, prefer compactMap, which skips the bad pieces, or check each result yourself.
Splitting and joining
The opposite operation is joined(separator:) on an array of strings. Splitting a sentence and joining the words with another separator rewrites the separators: "hello world foo".split(separator: " ").joined(separator: "-") gives hello-world-foo. This works on the array of Substring values directly, so no conversion is needed first.
The exercise
The constant sentence holds "hello world foo". Declare words with let and split the sentence at each space. The loop already in the starter code prints one word per line.
let sentence = "hello world foo"
let words = sentence.split(separator: " ")
for word in words { print(word) }
hello
world
foo
Common mistakes
- Expecting
[String]. The result holdsSubstringvalues. Assigning one to aStringvariable is a compile error until you wrap it inString(...). - Expecting empty strings.
"a,,b".split(separator: ",")has two pieces, not three, unless you passomittingEmptySubsequences: false. - Forgetting the label. Swift requires
separator:. - Splitting on the wrong character. A line from a file may end with a newline, or words may be separated by a tab; use
split(whereSeparator:)then.
Key takeaways
split(separator:)returns an array ofSubstringvalues and leaves out the separators.- Empty pieces are omitted unless you ask to keep them.
- Use
String(...)ormap { String($0) }to get real strings.
