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
| Operation | Code |
|---|---|
| Length / empty | s.count, s.isEmpty |
| Contains | s.contains("swi") |
| Prefix / suffix test | s.hasPrefix("he"), s.hasSuffix("ft") |
| Case | s.uppercased(), s.lowercased() |
| Replace | s.replacingOccurrences(of: "l", with: "L") |
| Trim | s.trimmingCharacters(in: .whitespacesAndNewlines) |
| Split | s.split(separator: " ") returns [Substring] |
| Join | ["a", "b"].joined(separator: ", ") |
| Repeat | String(repeating: "ab", count: 3) |
| Reverse | String(s.reversed()) |
| Pad numbers | String(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]