Dans Swift 4, je reçois cette erreur lorsque j'essaie de prendre un Substring
d'un String
à l'aide de la syntaxe en indice.
'indice' n'est pas disponible: impossible d'indiquer la chaîne avec un objet CountableClosedRange, voir le commentaire sur la documentation pour en savoir plus
Par exemple:
let myString: String = "foobar"
let mySubstring: Substring = myString[1..<3]
Deux questions:
"palindrome"[1..<3]
et "palindrome"[1...3]
, utilisez ces extensions.Swift 4
extension String {
subscript (bounds: CountableClosedRange<Int>) -> String {
let start = index(startIndex, offsetBy: bounds.lowerBound)
let end = index(startIndex, offsetBy: bounds.upperBound)
return String(self[start...end])
}
subscript (bounds: CountableRange<Int>) -> String {
let start = index(startIndex, offsetBy: bounds.lowerBound)
let end = index(startIndex, offsetBy: bounds.upperBound)
return String(self[start..<end])
}
}
Swift 3
Pour Swift 3 remplace par return self[start...end]
et return self[start..<end]
.
String.Index
.Ceci est la documentation à laquelle l'erreur Xcode fait référence.
Plus d'informations sur les encodages de chaînes comme UTF-8 et UTF-16
Votre question (et votre réponse personnelle) a 2 problèmes:
L'indexation d'une chaîne avec Int
n'a jamais été disponible dans la bibliothèque standard de Swift. Ce code est invalide depuis aussi longtemps que Swift existe:
let mySubstring: Substring = myString[1..<3]
La nouvelle String.Index(encodedOffset: )
renvoie un index au codage UTF-16 (16 bits). La chaîne de Swift utilise Extended Grapheme Cluster, qui peut prendre entre 8 et 64 bits pour stocker un caractère. Les émojis font une très bonne démonstration:
let myString = "????????????????????????????????"
let lowerBound = String.Index(encodedOffset: 1)
let upperBound = String.Index(encodedOffset: 3)
let mySubstring = myString[lowerBound..<upperBound]
// Expected: Canadian and UK flags
// Actual : gibberish
print(mySubstring)
En fait, obtenir le String.Index
N'a pas du tout changé dans Swift 4, pour le meilleur ou pour le pire:
let myString = "????????????????????????????????"
let lowerBound = myString.index(myString.startIndex, offsetBy: 1)
let upperBound = myString.index(myString.startIndex, offsetBy: 3)
let mySubstring = myString[lowerBound..<upperBound]
print(mySubstring)
- Comment puis-je résoudre cette erreur?
Cette erreur signifie que vous ne pouvez pas utiliser un int au format indice - vous devez utiliser un String.Index, que vous pouvez initialiser avec un encodedOffset Int.
let myString: String = "foobar"
let lowerBound = String.Index.init(encodedOffset: 1)
let upperBound = String.Index.init(encodedOffset: 3)
let mySubstring: Substring = myString[lowerBound..<upperBound]
- Où se trouve "le commentaire de documentation pour discussion" auquel il est fait référence dans l'erreur?
Il se trouve sur GitHub dans le référentiel Swift de la bibliothèque standard, dans un fichier intitulé UnavailableStringAPIs.Swift.gyb, situé au bas d'un classeur verrouillé, coincé dans des toilettes désaffectées avec une pancarte indiquant "Méfiez-vous du léopard". lien
Basé sur réponse de p-Sun
Swift 4
extension StringProtocol {
subscript(bounds: CountableClosedRange<Int>) -> SubSequence {
let start = index(startIndex, offsetBy: bounds.lowerBound)
let end = index(start, offsetBy: bounds.count)
return self[start..<end]
}
subscript(bounds: CountableRange<Int>) -> SubSequence {
let start = index(startIndex, offsetBy: bounds.lowerBound)
let end = index(start, offsetBy: bounds.count)
return self[start..<end]
}
}
Changements notables:
StringProtocol
. Cela permet aux utilisateurs tels que Substring
d'obtenir également ces indices.String
. La méthode index
est O(n) où n est le décalage par rapport à i.S'appuyant sur les réponses (p-Sun) et celles de Justin Oroz , voici deux extensions qui protègent contre les index non valides au-delà du début et de la fin d'une chaîne (ces extensions évitent également de réanalyser la chaîne). à partir du début, juste pour trouver l'index à la fin de la plage):
extension String {
subscript(bounds: CountableClosedRange<Int>) -> String {
let lowerBound = max(0, bounds.lowerBound)
guard lowerBound < self.count else { return "" }
let upperBound = min(bounds.upperBound, self.count-1)
guard upperBound >= 0 else { return "" }
let i = index(startIndex, offsetBy: lowerBound)
let j = index(i, offsetBy: upperBound-lowerBound)
return String(self[i...j])
}
subscript(bounds: CountableRange<Int>) -> String {
let lowerBound = max(0, bounds.lowerBound)
guard lowerBound < self.count else { return "" }
let upperBound = min(bounds.upperBound, self.count)
guard upperBound >= 0 else { return "" }
let i = index(startIndex, offsetBy: lowerBound)
let j = index(i, offsetBy: upperBound-lowerBound)
return String(self[i..<j])
}
}
extension String {
subscript(bounds: CountableClosedRange<Int>) -> String {
let lowerBound = max(0, bounds.lowerBound)
guard lowerBound < self.count else { return "" }
let upperBound = min(bounds.upperBound, self.count-1)
guard upperBound >= 0 else { return "" }
let i = index(startIndex, offsetBy: lowerBound)
let j = index(i, offsetBy: upperBound-lowerBound)
return String(self[i...j])
}
subscript(bounds: CountableRange<Int>) -> String {
let lowerBound = max(0, bounds.lowerBound)
guard lowerBound < self.count else { return "" }
***let upperBound = min(bounds.upperBound, self.count-1)***
guard upperBound >= 0 else { return "" }
let i = index(startIndex, offsetBy: lowerBound)
let j = index(i, offsetBy: upperBound-lowerBound)
return String(self[i..<j])
}
}
Vous obtenez cette erreur parce que le résultat de l'indice avec la plage est Substring?
pas Substring
.
Vous devez utiliser le code suivant:
let myString: String = "foobar"
let mySubstring: Substring? = myString[1..<3]