457 votes

Comment fonctionne la sous-chaîne de caractères dans Swift

J'ai eu la mise à jour de certains de mes vieux code et réponses avec Swift 3, mais quand je suis arrivé à Swift de Cordes et de l'Indexation avec des sous-chaînes les choses se sont source de confusion.

Plus précisément j'ai essayé le suivant:

let str = "Hello, playground"
let prefixRange = str.startIndex..<str.startIndex.advancedBy(5)
let prefix = str.substringWithRange(prefixRange)

d'où la deuxième ligne a été de me donner l'erreur suivante

Valeur de type 'String' est pas membre de 'substringWithRange'

Je vois qu' String n'ont méthodes suivantes maintenant:

str.substring(to: String.Index)
str.substring(from: String.Index)
str.substring(with: Range<String.Index>)

Elles étaient vraiment déroutant moi au début j'ai donc commencé à jouer autour de l'index et de la plage. C'est une suite de question et de réponse pour les sous-chaîne. Je suis l'ajout d'une réponse ci-dessous pour montrer comment ils sont utilisés.

985voto

Suragch Points 197

enter image description here

Tous les exemples suivants utilisent

var str = "Hello, playground"

Swift 4

Les chaînes eu une grosse refonte Swift 4. Lorsque vous obtenez des sous-chaîne d'une Chaîne de maintenant, vous obtenez une Substring type de retour plutôt qu'un String. Pourquoi est-ce? Les chaînes de valeur sont les types de Swift. Cela signifie que si vous utilisez une Ficelle pour faire un nouveau, alors, il doit être copié. C'est bon pour la stabilité (pas d'autre va le modifier à votre insu), mais mauvais pour l'efficacité.

Une sous-Chaîne, d'autre part, est une référence à la Chaîne d'origine à partir de laquelle il est venu. Voici une image de la documentation illustrant que.

Aucune copie est nécessaire de sorte qu'il est beaucoup plus efficace à utiliser. Cependant, imaginez que vous avez une dizaine de sous-Chaîne de caractères à partir d'un million de Chaîne de caractères. Parce que la sous-Chaîne est de référencement de la Chaîne, le système de aurait à tenir sur l'ensemble de la Chaîne, tant que la sous-Chaîne est d'environ. Ainsi, chaque fois que vous avez terminé la manipulation de votre sous-Chaîne, de les convertir en une Chaîne de caractères.

let myString = String(mySubstring)

Cela va copier la sous-chaîne-dessus et de la vieille Chaîne peut être nettoyée. Les sous-chaînes (type a) sont destinés à être de courte durée.

Une autre grande amélioration dans Swift 4 est que les Chaînes de caractères sont des Collections (encore une fois). Cela signifie que tout ce que vous pouvez faire pour une Collection, vous pouvez le faire en une Chaîne (utiliser des indices, itérer sur les personnages, filtre, etc).

Les exemples suivants montrent comment obtenir une sous-chaîne dans Swift.

L'obtention de sous-chaînes

Vous pouvez obtenir une sous-chaîne d'une chaîne à l'aide des indices ou un certain nombre d'autres méthodes (par exemple, prefix, suffix, split). Vous devez toujours utiliser String.Index et pas un Int pour l'indice de gamme. (Voir mon autre réponse, si vous avez besoin d'aide avec cela.)

Début d'une chaîne

Vous pouvez utiliser un indice (note de la Swift 4 unilatérale de gamme):

let index = str.index(str.startIndex, offsetBy: 5)
let mySubstring = str[..<index] // Hello

ou prefix:

let index = str.index(str.startIndex, offsetBy: 5)
let mySubstring = str.prefix(upTo: index) // Hello

ou encore plus simple:

let mySubstring = str.prefix(5) // Hello

Fin d'une chaîne

À l'aide des indices:

let index = str.index(str.endIndex, offsetBy: -10)
let mySubstring = str[index...] // playground

ou suffix:

let index = str.index(str.endIndex, offsetBy: -10)
let mySubstring = str.suffix(from: index) // playground

ou encore plus simple:

let mySubstring = str.suffix(10) // playground

Notez que lors de l'utilisation de l' suffix(from: index) j'ai eu à faire le compte à rebours à partir de la fin à l'aide -10. Ce n'est pas nécessaire quand il vient à l'aide d' suffix(x), ce qui prend tout de dernier x caractères d'une Chaîne.

Gamme dans une chaîne de caractères

De nouveau nous avons simplement utiliser des indices ici.

let start = str.index(str.startIndex, offsetBy: 7)
let end = str.index(str.endIndex, offsetBy: -6)
let range = start..<end

let mySubstring = str[range]  // play

Convertir Substring de String

N'oubliez pas, lorsque vous êtes prêt à enregistrer votre chaîne, vous devez le convertir en String , de sorte que le vieux de la chaîne de la mémoire peut être nettoyé.

let myString = String(mySubstring)

À l'aide d'un Int de l'indice de l'extension?

J'hésite à utiliser un Int index de base de l'extension après la lecture de l'article de Chaînes dans Swift 3 par Vitesse de Vitesse et Ole Begemann. Bien que dans Swift 4, les Chaînes sont des collections, la Swift de l'équipe délibérément n'a pas utilisé Int index. Il est encore String.Index. Cela a à voir avec la Swift Caractères étant composé d'un nombre variable d'Unicode codepoints. L'indice réel doit être unique calculée pour chaque chaîne.

Je dois dire, j'espère que l'équipe Swift trouve un moyen de faire abstraction String.Index dans le futur. Mais jusqu'à eux, je me suis choisissent d'utiliser leur API. Il m'aide à me souvenir que les manipulations de chaînes ne sont pas de simples Int de l'indice des recherches.

272voto

Zoff Dino Points 5010

Je suis vraiment frustré par le modèle d'accès String de Swift: tout doit être un Index . Tout ce que je veux, c'est accéder au ième caractère de la chaîne à l'aide de Int , et non de l'index maladroit et de l'avancement (ce qui change à chaque version majeure). J'ai donc fait une extension à String :

 extension String {
    func index(from: Int) -> Index {
        return self.index(startIndex, offsetBy: from)
    }

    func substring(from: Int) -> String {
        let fromIndex = index(from: from)
        return substring(from: fromIndex)
    }

    func substring(to: Int) -> String {
        let toIndex = index(from: to)
        return substring(to: toIndex)
    }

    func substring(with r: Range<Int>) -> String {
        let startIndex = index(from: r.lowerBound)
        let endIndex = index(from: r.upperBound)
        return substring(with: startIndex..<endIndex)
    }
}

let str = "Hello, playground"
print(str.substring(from: 7))         // playground
print(str.substring(to: 5))           // Hello
print(str.substring(with: 7..<11))    // play
 

174voto

Lou Z. Points 921

Swift 4 Extension:

 extension String { 
    subscript(_ range: CountableRange<Int>) -> String { 
        let idx1 = index(startIndex, offsetBy: max(0, range.lowerBound))
        let idx2 = index(startIndex, offsetBy: min(self.count, range.upperBound))
        return String(self[idx1..<idx2])
    }    
}       
 

Usage:

 let s = "hello"
s[0..<3] // "hel"
s[3..<s.count] // "lo"
 

Ou unicode:

 let s = " 

22voto

gebirgsbaerbel Points 770

Swift 4

Dans swift 4 String conforme Collection. Au lieu de substring, nous devons maintenant utiliser un subscript. Donc si vous voulez couper la parole en "play" de "Hello, playground", vous pouvez le faire comme ceci:

var str = "Hello, playground"
let start = str.index(str.startIndex, offsetBy: 7)
let end = str.index(str.endIndex, offsetBy: -6)
let result = str[start..<end] // The result is of type Substring

Il est intéressant de savoir que cela va vous donner un Substring au lieu de String. C'est rapide et efficace comme d' Substring d'actions de stockage de la Chaîne originale. Cependant le partage de la mémoire de cette manière peut aussi facilement conduire à des fuites de mémoire.

C'est pourquoi vous devez copier le résultat dans une Chaîne, une fois que vous voulez nettoyer la Chaîne d'origine. Vous pouvez faire cela en utilisant le constructeur normal:

let newString = String(result)

Vous pouvez trouver plus d'informations sur le nouveau Substring de la classe dans la [documentation d'Apple].1

Donc, si vous avez par exemple obtenir un Range comme le résultat de l' NSRegularExpression, vous pouvez utiliser l'extension suivante:

extension String {

    subscript(_ range: NSRange) -> String {
        let start = self.index(self.startIndex, offsetBy: range.lowerBound)
        let end = self.index(self.startIndex, offsetBy: range.upperBound)
        let subString = self[start..<end]
        return String(subString)
    }

}

9voto

Rio Bautista Points 31

J'ai eu la même réaction initiale. Moi aussi j'ai été frustré par la façon dont la syntaxe et les objets de changer de façon si spectaculaire dans chaque version majeure.

Cependant, j'ai réalisé à partir de l'expérience de la façon dont j'ai toujours finit par subir les conséquences d'essayer de combattre le "changement" comme traiter avec des caractères multi-octets qui est inévitable si vous êtes à la recherche à un public mondial.

J'ai donc décidé de reconnaître et de respecter les efforts exercés par les ingénieurs d'Apple et de faire ma part de comprendre leur état d'esprit quand ils sont venus avec cette "horrible".

Au lieu de créer des extensions qui est juste une solution de contournement pour rendre votre vie plus facile (je ne dis pas qu'ils ont tort ou coûteux), pourquoi pas à comprendre comment les Chaînes sont maintenant conçues pour fonctionner.

Par exemple, j'ai eu ce code, qui a été de travailler sur Swift 2.2:

let rString = cString.substringToIndex(2)
let gString = (cString.substringFromIndex(2) as NSString).substringToIndex(2)
let bString = (cString.substringFromIndex(4) as NSString).substringToIndex(2)

et après avoir renoncé à essayer d'obtenir la même approche de travail par exemple, à l'aide des sous-Chaînes, j'ai enfin compris le concept de traitement de Chaînes de caractères comme une bidirectionnel collection pour laquelle j'ai fini avec cette version du même code:

let rString = String(cString.characters.prefix(2))
cString = String(cString.characters.dropFirst(2))
let gString = String(cString.characters.prefix(2))
cString = String(cString.characters.dropFirst(2))
let bString = String(cString.characters.prefix(2))

J'espère que cela contribue...

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X