Sie sind nicht der einzige, der die Lösung nicht finden konnte.
String
nicht implementiert RandomAccessIndexType
. Wahrscheinlich, weil sie Zeichen mit unterschiedlichen Bytelängen aktivieren. Deshalb müssen wir string.characters.count
( count
oder countElements
in Swift 1.x) verwenden, um die Anzahl der Zeichen zu erhalten. Das gilt auch für Positionen. Das _position
ist wahrscheinlich ein Index in das rohe Array von Bytes und sie wollen das nicht offenlegen. Das String.Index
soll uns vor dem Zugriff auf Bytes in der Mitte von Zeichen schützen.
Das bedeutet, dass jeder Index, den Sie erhalten, aus String.startIndex
oder String.endIndex
( String.Index
implementiert BidirectionalIndexType
) erstellt werden muss. Alle anderen Indizes können mit successor
oder predecessor
Methoden erstellt werden .
Um uns bei den Indizes zu helfen, gibt es eine Reihe von Methoden (Funktionen 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
Das Arbeiten mit String.Index
ist umständlich, aber die Verwendung eines Wrappers zum Indizieren nach Ganzzahlen (siehe https://stackoverflow.com/a/25152652/669586 ) ist gefährlich, da dadurch die Ineffizienz einer echten Indizierung verborgen wird.
Beachten Sie, dass die Swift-Indizierungsimplementierung das Problem hat, dass für eine Zeichenfolge erstellte Indizes / Bereiche nicht zuverlässig für eine andere Zeichenfolge verwendet werden können. Beispiel:
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]