Extracting substrings

How to:

Swift makes it pretty straightforward to work with substrings. Let’s dive right into it with some examples.

let fullString = "Hello, Swift Programmer!"
let startIndex = fullString.index(fullString.startIndex, offsetBy: 7)
let endIndex = fullString.index(fullString.startIndex, offsetBy: 12)

// Extracting a substring using String.Index
let substring = fullString[startIndex...endIndex]

print(substring) // "Swift"

// Another way, using NSRange and NSString
import Foundation

let nsRange = NSRange(location: 7, length: 6)
if let range = Range(nsRange, in: fullString) {
    let substring = fullString[range]
    print(substring) // "Swift"

// Short way, if you know the exact indices
let quickSubstring = fullString[7...12]

print(quickSubstring) // This will throw an error because Swift strings don't support integer indexing


// Error: 'subscript(_:)' is unavailable: cannot subscript String with an Int, see the documentation for String for more information

Deep Dive

Extracting substrings in Swift involves understanding how Swift handles strings, which is a bit different from languages like Python or C#. In Swift, strings are collections of characters that don’t use integer indexes. This stems from Swift’s support for Unicode-compliant characters, making strings not a fixed length, but rather a collection of grapheme clusters (what a user perceives as a single character).

This design means direct integer subscripting doesn’t fly with Swift strings; you need to work with String.Index. While it’s not as immediately intuitive as using integers, it handles various text scripts and emoji consistently.

Alternatives include using NSString from Objective-C, as shown in the examples, which allows for NSRange, but that’s kind of old-school and not Swifty. Since Swift 4, String itself got a lot of love, with richer, more intuitive API options to work with substrings, leaving NSString in the dust for most tasks.

Implementation details are crucial—naive substring extraction can lead to performance hits because each call to index(_: offsetBy:) can be O(n) when dealing with Unicode-compliant strings. Additionally, when you create a substring in Swift, it shares the memory of the original string, making it efficient, but something to be aware of if you mutate the original string later.

See Also

For more on this topic, hit up the official docs:

Get your hands dirty with practice and play around in a Swift playground to really get the hang of it.