Get nth character of a string in Swift
character, collections, string, subscript, swift
Solution
Attention: Please see Leo Dabus' answer for a proper implementation for Swift 4 and Swift 5.
Swift 4 or later
The `Substring` type was introduced in Swift 4 to make substrings faster and more efficient by sharing storage with the original string, so that's what the subscript functions should return.
Try it out here
extension StringProtocol {
subscript(offset: Int) -> Character { self[index(startIndex, offsetBy: offset)] }
subscript(range: Range<Int>) -> SubSequence {
let startIndex = index(self.startIndex, offsetBy: range.lowerBound)
return self[startIndex..<index(startIndex, offsetBy: range.count)]
}
subscript(range: ClosedRange<Int>) -> SubSequence {
let startIndex = index(self.startIndex, offsetBy: range.lowerBound)
return self[startIndex..<index(startIndex, offsetBy: range.count)]
}
subscript(range: PartialRangeFrom<Int>) -> SubSequence { self[index(startIndex, offsetBy: range.lowerBound)...] }
subscript(range: PartialRangeThrough<Int>) -> SubSequence { self[...index(startIndex, offsetBy: range.upperBound)] }
subscript(range: PartialRangeUpTo<Int>) -> SubSequence { self[..<index(startIndex, offsetBy: range.upperBound)] }
}
To convert the `Substring` into a `String`, you can simply do `String(string[0..2])`, but you should only do that if you plan to keep the substring around. Otherwise, it's more efficient to keep it a `Substring`.
It would be great if someone could figure out a good way to merge these two extensions into one. I tried extending `StringProtocol` without success, because the `index` method does not exist there. Note: This answer has been already edited, it is properly implemented and now works for substrings as well. Just make sure to use a valid range to avoid crashing when subscripting your StringProtocol type. For subscripting with a range that won't crash with out of range values you can use this implementation
Why is this not built-in?
The error message says "see the documentation comment for discussion". Apple provides the following explanation in the file UnavailableStringAPIs.swift:
Subscripting strings with integers is not available.
The concept of "the `i`th character in a string" has different interpretations in different libraries and system components. The correct interpretation should be selected according to the use case and the APIs involved, so `String` cannot be subscripted with an integer.
Swift provides several different ways to access the character data stored inside strings.
`String.utf8` is a collection of UTF-8 code units in the string. Use this API when converting the string to UTF-8. Most POSIX APIs process strings in terms of UTF-8 code units.
`String.utf16` is a collection of UTF-16 code units in string. Most Cocoa and Cocoa touch APIs process strings in terms of UTF-16 code units. For example, instances of `NSRange` used with `NSAttributedString` and `NSRegularExpression` store substring offsets and lengths in terms of UTF-16 code units.
`String.unicodeScalars` is a collection of Unicode scalars. Use this API when you are performing low-level manipulation of character data.
`String.characters` is a collection of extended grapheme clusters, which are an approximation of user-perceived characters.
Note that when processing strings that contain human-readable text, character-by-character processing should be avoided to the largest extent possible. Use high-level locale-sensitive Unicode algorithms instead, for example, `String.localizedStandardCompare()`, `String.localizedLowercaseString`, `String.localizedStandardRangeOfString()` etc.
Problem
How can I get the nth character of a string? I tried bracket(`[]`) accessor with no luck. ``` var string = "Hello, world!" var firstChar = string[0] // Throws error ``` ERROR: 'subscript' is unavailable: cannot subscript String with an Int, see the documentation comment for discussion