In Swift 4, I'm getting this error when I try to take a Substring
of a String
using subscript syntax.
'subscript' is unavailable: cannot subscript String with a CountableClosedRange, see the documentation comment for discussion
For example:
let myString: String = "foobar"
let mySubstring: Substring = myString[1..<3]
Two questions:
"palindrome"[1..<3]
and "palindrome"[1...3]
, use these extensions.Swift 4
extension String {
subscript (bounds: CountableClosedRange<Int>) -> String {
let start = index(startIndex, offsetBy: bounds.lowerBound)
let end = index(startIndex, offsetBy: bounds.upperBound)
return String(self[start...end])
}
subscript (bounds: CountableRange<Int>) -> String {
let start = index(startIndex, offsetBy: bounds.lowerBound)
let end = index(startIndex, offsetBy: bounds.upperBound)
return String(self[start..<end])
}
}
Swift 3
For Swift 3 replace with return self[start...end]
and return self[start..<end]
.
String.Index
.This is the documentation that Xcode error refers to.
More on String encodings like UTF-8 and UTF-16
Your question (and self-answer) has 2 problems:
Subscripting a string with Int
has never been available in Swift's Standard Library. This code has been invalid for as long as Swift exists:
let mySubstring: Substring = myString[1..<3]
The new String.Index(encodedOffset: )
returns an index in UTF-16 (16-bit) encoding. Swift's string uses Extended Grapheme Cluster, which can take between 8 and 64 bits to store a character. Emojis make for very good demonstration:
let myString = "πΊπΈπ¨π¦π¬π§π«π·"
let lowerBound = String.Index(encodedOffset: 1)
let upperBound = String.Index(encodedOffset: 3)
let mySubstring = myString[lowerBound..<upperBound]
// Expected: Canadian and UK flags
// Actual : gibberish
print(mySubstring)
In fact, getting the String.Index
has not changed at all in Swift 4, for better or worse:
let myString = "πΊπΈπ¨π¦π¬π§π«π·"
let lowerBound = myString.index(myString.startIndex, offsetBy: 1)
let upperBound = myString.index(myString.startIndex, offsetBy: 3)
let mySubstring = myString[lowerBound..<upperBound]
print(mySubstring)
You could just convert your string to an array of characters...
let aryChar = Array(myString)
Then you get all the array functionality...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With