Non sei l'unico che non è riuscito a trovare la soluzione.
Stringnon implementa RandomAccessIndexType. Probabilmente perché abilitano caratteri con diverse lunghezze di byte. Ecco perché dobbiamo usare string.characters.count( counto countElementsin Swift 1.x) per ottenere il numero di caratteri. Ciò vale anche per le posizioni. Il _positionè probabilmente un indice nella matrice di byte e non vogliono esporre questo. IlString.Index scopo è di proteggerci dall'accesso ai byte nel mezzo di caratteri.
Ciò significa che qualsiasi indice ottenuto deve essere creato da String.startIndexo String.endIndex( String.Indeximplementa BidirectionalIndexType). Qualsiasi altro indice può essere creato usando successoropredecessor metodi.
Ora per aiutarci con gli indici, c'è una serie di metodi (funzioni in Swift 1.x):
Swift 4.x
let text = "abc"
let index2 = text.index(text.startIndex, offsetBy: 2) //will call succ 2 times
let lastChar: Character = text[index2] //now we can index!
let characterIndex2 = text.index(text.startIndex, offsetBy: 2)
let lastChar2 = text[characterIndex2] //will do the same as above
let range: Range<String.Index> = text.range(of: "b")!
let index: Int = text.distance(from: text.startIndex, to: range.lowerBound)
Swift 3.0
let text = "abc"
let index2 = text.index(text.startIndex, offsetBy: 2) //will call succ 2 times
let lastChar: Character = text[index2] //now we can index!
let characterIndex2 = text.characters.index(text.characters.startIndex, offsetBy: 2)
let lastChar2 = text.characters[characterIndex2] //will do the same as above
let range: Range<String.Index> = text.range(of: "b")!
let index: Int = text.distance(from: text.startIndex, to: range.lowerBound)
Swift 2.x
let text = "abc"
let index2 = text.startIndex.advancedBy(2) //will call succ 2 times
let lastChar: Character = text[index2] //now we can index!
let lastChar2 = text.characters[index2] //will do the same as above
let range: Range<String.Index> = text.rangeOfString("b")!
let index: Int = text.startIndex.distanceTo(range.startIndex) //will call successor/predecessor several times until the indices match
Swift 1.x
let text = "abc"
let index2 = advance(text.startIndex, 2) //will call succ 2 times
let lastChar: Character = text[index2] //now we can index!
let range = text.rangeOfString("b")
let index: Int = distance(text.startIndex, range.startIndex) //will call succ/pred several times
Lavorare con String.Indexè ingombrante ma usare un wrapper per indicizzare per numeri interi (vedi https://stackoverflow.com/a/25152652/669586 ) è pericoloso perché nasconde l'inefficienza dell'indicizzazione reale.
Si noti che l'implementazione dell'indicizzazione Swift ha il problema che gli indici / intervalli creati per una stringa non possono essere utilizzati in modo affidabile per una stringa diversa , ad esempio:
Swift 2.x
let text: String = "abc"
let text2: String = "🎾🏇🏈"
let range = text.rangeOfString("b")!
//can randomly return a bad substring or throw an exception
let substring: String = text2[range]
//the correct solution
let intIndex: Int = text.startIndex.distanceTo(range.startIndex)
let startIndex2 = text2.startIndex.advancedBy(intIndex)
let range2 = startIndex2...startIndex2
let substring: String = text2[range2]
Swift 1.x
let text: String = "abc"
let text2: String = "🎾🏇🏈"
let range = text.rangeOfString("b")
//can randomly return nil or a bad substring
let substring: String = text2[range]
//the correct solution
let intIndex: Int = distance(text.startIndex, range.startIndex)
let startIndex2 = advance(text2.startIndex, intIndex)
let range2 = startIndex2...startIndex2
let substring: String = text2[range2]