String slicing is somewhat verbose in Swift. If you’re coming from another language, it’s not immediately obvious how to do it at all.
Many of us end up cursing the screen after trying to get substrings using patterns from other languages. If you feel the same way, you may have run into something like this:
let str = "π Reading π is π FUNdamental! π" let substr = str[0] // error: 'subscript' is unavailable: cannot subscript String with an Int let substr = str[0..<5] // error: 'subscript' is unavailable: cannot subscript String with a CountableRange<Int>
Swift Strings use a non-integer index type for reasons of speed and safety:
- Speed: because an index access will always be a constant-time operation.
- Safety: because you’re guaranteed to get a whole character and not, say, half of a 16-bit character.
I know what you’re thinking: that’s swell and all, but I just want to grab a range of characters. Here’s how you do that.
String
has a few methods to get a Substring
using integer arguments:
func prefix(Int) -> Substring func suffix(Int) -> Substring func dropFirst(Int) -> Substring func dropLast(Int) -> Substring
Here are some examples:
let str = "π Reading π is π FUNdamental! π" str.prefix(1) // π str.suffix(1) // π str.dropFirst(2).prefix(9) as Substring // Reading π str.dropFirst(2).dropLast(2) as Substring // Reading π is π FUNdamental!
There some more methods that return indexes.
func startIndex -> String.Index func index(after: String.Index) -> String.Index func index(String.Index, offsetBy: Int) -> String.Index
Here are some examples of those:
let str = "π Reading π is π FUNdamental! π" let start = str.startIndex let tenth = str.index(start, offsetBy: 10) let eleventh = str.index(after: tenth) let books = str[tenth..<eleventh] // π
Note that subscripting with string indexes is constant time, but creating the index can be
linear time. So if youβre advancing through the string, or if you repeatedly access
indexed values, itβs better to keep a current index position than to repeatedly advance
from the beginning of the string.
In other words, this:
let start = str.startIndex let tenth = str.index(start, offsetBy: 10) let sixteenth = str.index(tenth, offsetBy: 6) for i in 1...1000 { let books = str[tenth..<sixteenth] // π is π }
is better than this:
for i in 1...1000 { let start = str.startIndex let tenth = str.index(start, offsetBy: 10) let sixteenth = str.index(tenth, offsetBy: 6) let books = str[tenth..<sixteenth] // π is π }
or this:
for i in 1...1000 { let books = str.dropFirst(10).prefix(6) as Substring // π is π }
Note that these are by no means a complete set of methods. If you come across any other useful methods or patterns of accessing substrings, let me know.