Swift Cheatsheet

Strings, Ranges & Indexes

Use this Swift reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.

Grapheme clusters, not bytes

let word = "café"
word.count                    // 4 characters
word.utf8.count               // 5 bytes, é is 2 bytes in UTF-8

let flag = "🇨🇦"
flag.count                    // 1 Character (one grapheme cluster)
flag.unicodeScalars.count     // 2 regional-indicator scalars
flag.utf8.count               // 8 bytes

"é" == "e\u{301}"             // true, canonical equivalence

String.count counts user-perceived characters (extended grapheme clusters). That is why Swift string indices are opaque instead of integers: byte offsets do not line up with characters.

Indexes and slicing

let s = "hello swift"

let i = s.index(s.startIndex, offsetBy: 4)
s[i]                                  // "o"
s[..<i]                               // "hell" (a Substring)
s.index(after: i)
s.index(before: i)

if let space = s.firstIndex(of: " ") {
    let first = s[..<space]                       // "hello", shares storage
    let rest = String(s[s.index(after: space)...])   // "swift"
}

// For index-heavy algorithms, convert once
let chars = Array(s)                  // [Character], O(1) subscripting
chars[4]                              // "o"

Substring shares its parent's storage and keeps the parent alive. Wrap in String(...) before storing long-term.

Common operations

OperationCode
Length / emptys.count, s.isEmpty
Containss.contains("swi")
Prefix / suffix tests.hasPrefix("he"), s.hasSuffix("ft")
Cases.uppercased(), s.lowercased()
Replaces.replacingOccurrences(of: "l", with: "L")
Trims.trimmingCharacters(in: .whitespacesAndNewlines)
Splits.split(separator: " ") returns [Substring]
Join["a", "b"].joined(separator: ", ")
RepeatString(repeating: "ab", count: 3)
ReverseString(s.reversed())
Pad numbersString(format: "%05d", 42)

replacingOccurrences, trimmingCharacters, and String(format:) need import Foundation.

Building strings

let name = "Ada"
let score = 97
let line = "\(name): \(score) (\(Double(score) / 100))"

let multi = """
    Line one
    Line two with \(name)
    """                       // closing quotes set the indentation baseline

let raw = #"He said "hi" and \n stays literal"#
let rawInterp = #"value = \#(score)"#     // interpolation inside raw strings

Character and ASCII work for algorithms

let c: Character = "x"
c.isLetter
c.isNumber
c.isWhitespace
c.isUppercase
c.asciiValue                  // UInt8?, nil for non-ASCII
c.wholeNumberValue            // Int?, Character("7") gives 7

let bytes = Array("abc".utf8)                 // [97, 98, 99]
let letterIndex = Int(bytes[0] - UInt8(ascii: "a"))   // 0
String(UnicodeScalar(97))                     // "a"

For ASCII-only problems, working over Array(s.utf8) is much faster than String indexing.

Ranges and stride

0..<5                          // Range<Int>, excludes 5
1...5                          // ClosedRange<Int>, includes 5

for i in (0..<5).reversed() { print(i) }           // 4 3 2 1 0
for i in stride(from: 0, to: 10, by: 3) { }        // 0 3 6 9
for i in stride(from: 10, through: 0, by: -5) { }  // 10 5 0

let r = 1...10
r.contains(7)                  // true
r.lowerBound                   // 1
r.upperBound                   // 10

let xs = [10, 20, 30, 40]
xs[2...]                       // one-sided ranges slice collections
xs[..<2]