的問題是,即使String.Index
確實符合Comparable
協議,你還需要指定要與public struct Range<Bound> where Bound : Comparable {}
注意上班範圍類型:作爲NSString
使用UTF-16,檢查this和同樣在您提到的link中,您的初始代碼對於包含多個UTF-16代碼點的字符無法正常工作。以下是更新工作版本的雨燕3.
extension Range where Bound == String.Index {
init(_ range: NSRange, in string: String) {
let lower16 = string.utf16.index(string.utf16.startIndex, offsetBy: range.location)
let upper16 = string.utf16.index(string.utf16.startIndex, offsetBy: NSMaxRange(range))
if let lower = lower16.samePosition(in: string),
let upper = upper16.samePosition(in: string) {
self.init(lower..<upper)
} else {
fatalError("init(range:in:) could not be implemented")
}
}
}
let string = "❄️Let it snow! ☃️"
let range1 = NSRange(location: 0, length: 1)
let r1 = Range<String.Index>(range1, in: string) // ❄️
let range2 = NSRange(location: 1, length: 2)
let r2 = Range<String.Index>(range2, in: string) // fatal error: init(range:in:) could not be implemented
要回答OP的評論:問題是一個NSString對象編碼兼容Unicode的文本字符串,表示爲一個序列UTF-16編碼單元。構成字符串內容的Unicode標量值可以長達21位。較長的標量值可能需要兩個UInt16值進行存儲。
因此,像❄️這樣的字母在NSString中佔用了兩個UInt16值,但在String中只有一個。當你將一個NSRange參數傳遞給初始值設定項時,你可能會期望它在NSString中正常工作。
在我的例子,對於r1
和r2
結果後,你轉換到string
UTF16是「❄️」和一個致命的錯誤。同時,您最初解決方案的結果分別是'❄️L'和'Le'。希望你看到不同之處。
如果你堅持使用解決方案而不轉換爲utf16,你可以看看the Swift source code做出決定。在Swift 4中,你將初始化器作爲一個內置的lib。代碼如下。
extension Range where Bound == String.Index {
public init?(_ range: NSRange, in string: String) {
let u = string.utf16
guard range.location != NSNotFound,
let start = u.index(u.startIndex, offsetBy: range.location, limitedBy: u.endIndex),
let end = u.index(u.startIndex, offsetBy: range.location + range.length, limitedBy: u.endIndex),
let lowerBound = String.Index(start, within: string),
let upperBound = String.Index(end, within: string)
else { return nil }
self = lowerBound..<upperBound
}
}
相關:[NSRange到範圍](https://stackoverflow.com/questions/25138339/nsrange-to-rangestring-index) –
ma11hew28