Vous n'êtes pas le seul à ne pas trouver la solution.
String
ne met pas en œuvre RandomAccessIndexType
. Probablement parce qu'ils permettent des caractères avec des longueurs d'octets différentes. C'est pourquoi nous devons utiliser string.characters.count
( count
ou countElements
dans Swift 1.x) pour obtenir le nombre de caractères. Cela s'applique également aux postes. Il _position
s'agit probablement d'un index dans le tableau brut d'octets et ils ne veulent pas l'exposer. Le String.Index
est destiné à nous protéger de l'accès aux octets au milieu des caractères.
Cela signifie que tout index que vous obtenez doit être créé à partir de String.startIndex
ou String.endIndex
( String.Index
implémente BidirectionalIndexType
). Tout autre indice peut être créé à l'aide des méthodes successor
ou predecessor
.
Maintenant, pour nous aider avec les indices, il existe un ensemble de méthodes (fonctions dans 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
Travailler avec String.Index
est lourd mais utiliser un wrapper pour indexer par des entiers (voir https://stackoverflow.com/a/25152652/669586 ) est dangereux car il cache l'inefficacité d'une véritable indexation.
Notez que l'implémentation de l'indexation Swift a le problème que les index / plages créés pour une chaîne ne peuvent pas être utilisés de manière fiable pour une chaîne différente , par exemple:
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]