Edit: See the second code example instead! Please disregard the first block; I didn't read the question as carefully as I should have, so it is not a relevant solution.
Edit 2: Also look at the first comment below this answer for an example of a major caveat of the first example. It does not work correctly for strings which contain emojis. Credit to Leo Dabus for this discovery.
This code might do what you're looking for, but I can't guarantee its reliability in all cases.
What it does is take a regular half-open range of integers (of the form a..<b
) and a specific string (because, as matt mentioned in his comment, Swift string indices don't pertain to the class String
, only to some particular string), and returns an open range of indices for that particular string.
In effect, it just adds 1 to the lower bound to change it from inclusive to exclusive.
import Foundation
// Returns a Range of 'String.Index'es where both upper and lower bounds are exclusive.
extension Range {
// Here, the upper bound of the range was already exclusive, so don't subtract 1 from it. Only add 1 to the lower bound.
static func OpenRange(string: String, range: Range<Int>) -> Range<String.Index> {
return Range<String.Index>(uncheckedBounds: (String.Index(utf16Offset: range.lowerBound + 1, in: string), String.Index(utf16Offset: range.upperBound, in: string)))
}
}
let theString = "abcdefg"
let endIndex = theString.index(theString.startIndex, offsetBy: 5)
let range: Range<String.Index> = theString.startIndex..<endIndex
let openRange = Range<String.Index>.OpenRange(string: theString, range: 0..<5)
print(theString[range]) // prints 'abcde'
print(theString[openRange]) // prints 'bcde'
Reference: https://www.avanderlee.com/swift/ranges-explained/
The example I had above doesn't really fit the specific case you were asking about though, as I was starting from code I already had and was trying to 'adapt' it to this situation. My bad! I believe this is a better alternative:
// Returns a Range of 'String.Index'es between two specified characters in the string (as exclusive bounds)
extension Range {
// Here, the upper bound of the range was already exclusive, so don't subtract 1 from it. Only add 1 to the lower bound.
static func OpenRange(string: String, from: String, to: String) -> Range<String.Index> {
// The 'firstIndex' method expects a Character, not a String, so you need a type cast here
let lowerInclusive = string.firstIndex(of: Character(from))!
let lowerExclusive = string.index(lowerInclusive, offsetBy: 1)
let upperExclusive = string.firstIndex(of: Character(to))!
return Range<String.Index>(uncheckedBounds: (lowerExclusive, upperExclusive))
}
}
let theString = "[10:02.11]"
let openRange1 = Range<String.Index>.OpenRange(string: theString, from: "[", to: ":")
let openRange2 = Range<String.Index>.OpenRange(string: theString, from: ":", to: "]")
print(theString[openRange1]) // prints '10'
print(theString[openRange2]) // prints '02.11'