What a string is in Swift
A String is an ordered collection of Character values. You write one with double quotes, and Swift infers the type:
let greeting = "Hello"
var name = "Andy"
name += "!"
print(greeting, name, name.count)
Hello Andy! 5
The chapter that starts here uses strings in interview-style problems: reversing, comparing and splitting them. Swift's strings behave differently from those in many other languages, so it helps to know the three ideas below before you start.
Idea 1: a Character is what a reader sees as one letter
A Character is a single visible character, even when Unicode stores it as several pieces. The letter "e" followed by a combining accent is one Character made of two Unicode scalars and three bytes in UTF-8:
let e = "e\u{301}"
print(e.count, e.unicodeScalars.count, e.utf8.count)
1 2 3
This is why count counts characters, and why finding the length of a string means walking through it: characters have different sizes in memory, so Swift cannot jump to the n-th one directly.
Idea 2: no integer subscripts
Because of that, str[2] is a compile error. To reach a position you build a String.Index:
let s = "Hello"
let idx = s.index(s.startIndex, offsetBy: 2)
print(s[idx])
l
An offset past the end stops the program with an "index out of bounds" error. When a problem needs many positional reads or writes, convert the string first with Array(s). An array of characters can be indexed with plain integers and changed in place, and String(chars) turns it back into a string.
Slicing a string gives a Substring, a view into the original text. Wrap it in String(...) to get an independent string:
let str = "JavaScript"
let start = str.index(str.startIndex, offsetBy: 2)
let end = str.index(str.startIndex, offsetBy: 6)
let sub = str[start..<end]
print(sub, String(sub))
vaSc vaSc
Idea 3: strings are values
A String is a value type: assigning it to another variable copies it, and changing one copy never affects the other. let makes a string constant, var makes it changeable. There is no way to modify one character of a string in place, so "changing" a character means building a new string. Building a string character by character with += is fine, but prepending to the front each time copies the whole string again, so a loop that does it takes O(n²) time.
Two more details come up in the problems:
+joins twoStringvalues, but it does not accept aCharacter. WriteString(ch) + rest. The compiler reports that it cannot convert a value of typeCharacterto the expected argument typeString.- Comparing strings with
==compares their contents, so"apple" == "apple"istrue.
Everyday operations
You will meet a few members of String again and again. All of these were run on let s = "Hello":
print(s.uppercased(), s.hasPrefix("He"), s.contains("ell"), s.isEmpty)
print(s.prefix(2), s.suffix(3), s.dropLast())
let name = "Ada"
print("Hi \(name), \(3 * 2)")
HELLO true true false
He llo Hell
Hi Ada, 6
The last line uses string interpolation: \(expression) inside a literal inserts the value of the expression. Iterating is direct as well. for ch in s visits each Character in order, and s.reversed() gives the characters back to front, which String(...) turns into a string again.
Splitting and joining are the other pair to remember: split(separator: " ") breaks a string into an array of Substring values, and joined(separator:) on an array of strings builds one string from many pieces, which is cheaper than appending in a long chain.
Key takeaways
- A
Stringis a collection ofCharactervalues, andcountcounts characters. - Index with
String.Indexor convert toArray(s)when you need integer positions. - Slices are
Substringvalues; wrap them inString(...)to keep them. - Strings are values, so any change builds a new string. Plan for that when a loop edits one.
