J'ai mis à jour certains de mes anciens codes et réponses avec Swift 3, mais quand je suis arrivé à Swift Strings et Indexing with substrings, les choses sont devenues confuses.
Plus précisément, j'essayais ce qui suit:
let str = "Hello, playground"
let prefixRange = str.startIndex..<str.startIndex.advancedBy(5)
let prefix = str.substringWithRange(prefixRange)
où la deuxième ligne me donnait l'erreur suivante
La valeur de type 'String' n'a pas de membre 'substringWithRange'
Je vois que String
cela a maintenant les méthodes suivantes:
str.substring(to: String.Index)
str.substring(from: String.Index)
str.substring(with: Range<String.Index>)
Cela m'a vraiment dérouté au début, alors j'ai commencé à jouer sur l' index et la plage . Il s'agit d'une question et réponse de suivi pour la sous-chaîne. J'ajoute une réponse ci-dessous pour montrer comment ils sont utilisés.
Réponses:
Tous les exemples suivants utilisent
Swift 4
Les chaînes ont subi une refonte assez importante dans Swift 4. Lorsque vous obtenez une sous-chaîne à partir d'une chaîne maintenant, vous récupérez un
Substring
type plutôt qu'unString
. Pourquoi est-ce? Les chaînes sont des types de valeur dans Swift. Cela signifie que si vous utilisez une chaîne pour en créer une nouvelle, elle doit être copiée. C'est bon pour la stabilité (personne d'autre ne va le changer à votre insu) mais mauvais pour l'efficacité.Une sous-chaîne, d'autre part, est une référence à la chaîne d'origine dont elle est issue. Voici une image de la documentation illustrant cela.
Aucune copie n'est nécessaire, il est donc beaucoup plus efficace à utiliser. Cependant, imaginez que vous ayez une sous-chaîne de dix caractères à partir d'une chaîne d'un million de caractères. Étant donné que la sous-chaîne fait référence à la chaîne, le système doit conserver la chaîne entière aussi longtemps que la sous-chaîne est présente. Ainsi, chaque fois que vous avez fini de manipuler votre sous-chaîne, convertissez-la en chaîne.
Cela ne copiera que la sous-chaîne et la mémoire contenant l'ancienne chaîne peut être récupérée . Les sous-chaînes (en tant que type) sont censées être de courte durée.
Une autre grande amélioration dans Swift 4 est que les cordes sont des collections (encore). Cela signifie que tout ce que vous pouvez faire pour une collection, vous pouvez le faire pour une chaîne (utilisez des indices, parcourez les caractères, filtrez, etc.).
Les exemples suivants montrent comment obtenir une sous-chaîne dans Swift.
Obtention de sous-chaînes
Vous pouvez obtenir une chaîne d'une chaîne à l'aide ou plusieurs indices d'autres méthodes (par exemple
prefix
,suffix
,split
). Cependant, vous devez toujours utiliserString.Index
et non unInt
index pour la plage. (Voir mon autre réponse si vous avez besoin d'aide à ce sujet.)Début d'une chaîne
Vous pouvez utiliser un indice (notez la plage unilatérale de Swift 4):
ou
prefix
:ou encore plus simple:
Fin d'une chaîne
Utilisation d'indices:
ou
suffix
:ou encore plus simple:
Notez que lors de l'utilisation du
suffix(from: index)
je devais recompter de la fin en utilisant-10
. Cela n'est pas nécessaire lors de l'utilisationsuffix(x)
, qui ne prend que les derniersx
caractères d'une chaîne.Plage dans une chaîne
Encore une fois, nous utilisons simplement des indices ici.
Conversion
Substring
enString
N'oubliez pas, lorsque vous êtes prêt à enregistrer votre sous-chaîne, vous devez la convertir en un
String
afin que la mémoire de l'ancienne chaîne puisse être nettoyée.Vous utilisez une
Int
extension d'index?J'hésite à utiliser une
Int
extension d'index basée après avoir lu l'article Strings dans Swift 3 par Airspeed Velocity et Ole Begemann. Bien que dans Swift 4, les chaînes soient des collections, l'équipe Swift n'a délibérément pas utilisé d'Int
index. C'est encoreString.Index
. Cela a à voir avec les caractères Swift étant composés de nombres variables de points de code Unicode. L'index réel doit être calculé de manière unique pour chaque chaîne.Je dois dire que j'espère que l'équipe Swift trouvera un moyen d'abstraire
String.Index
à l'avenir. Mais jusqu'à eux, je choisis d'utiliser leur API. Cela m'aide à me rappeler que les manipulations de chaînes ne sont pas seulement de simplesInt
recherches d'index.la source
garbage collected
;-) J'espère que les gens d'ici savent qu'il n'y a pas de collecte des ordures dans Swift.Je suis vraiment frustré par le modèle d'accès aux chaînes 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 en utilisantInt
, pas l'index maladroit et en avançant (ce qui arrive à changer avec chaque version majeure). J'ai donc fait une extension àString
:la source
let str = "🇨🇭🇩🇪🇺🇸Hello"
print(str.substring(to: 2))
str[5]
, je veux accéder au caractère à l'index 5, quel que soit ce caractère ou combien d'octets il faut. Swift n'est-il pas tout au sujet de la productivité du développeur?countElement(str)
pour trouver la longueur. Dans Swift 3, Apple a rendu la chaîne non conformeSequence
et a forcé tout le monde à l'utiliser à lastr.characters
place. Ces gars-là n'ont pas peur de faire des changements. Leur entêtement sur l'indice entier est vraiment difficile à comprendreExtension Swift 5:
Usage:
Ou unicode:
la source
count
n'était disponible que surself.characters
CountableClosedRange<Int>
si vous souhaitez écrire par exemples[0...2]
.Swift 4 et 5:
Comment l'utiliser:
la source
Swift 4
Dans swift 4
String
est conforme àCollection
. Au lieu desubstring
, nous devons maintenant utiliser unsubscript.
Donc , si vous voulez couper uniquement le mot"play"
de"Hello, playground"
, vous pouvez le faire comme ceci:Il est intéressant de savoir que cela vous donnera un
Substring
au lieu d'unString
. C'est rapide et efficace car ilSubstring
partage son stockage avec la chaîne d'origine. Cependant, le partage de la mémoire de cette manière peut également facilement entraîner des fuites de mémoire.C'est pourquoi vous devez copier le résultat dans une nouvelle chaîne, une fois que vous souhaitez nettoyer la chaîne d'origine. Vous pouvez le faire en utilisant le constructeur normal:
Vous pouvez trouver plus d'informations sur la nouvelle
Substring
classe dans la [documentation Apple]. 1Donc, si vous obtenez par exemple un
Range
résultat d'unNSRegularExpression
, vous pouvez utiliser l'extension suivante:la source
text[Range( nsRange , in: text)!]
Voici une fonction qui renvoie la sous-chaîne d'une sous-chaîne donnée lorsque des indices de début et de fin sont fournis. Pour une référence complète, vous pouvez visiter les liens ci-dessous.
Voici un lien vers le blog que j'ai créé pour traiter de la manipulation des chaînes dans swift. Manipulation des chaînes dans swift (couvre également swift 4)
Ou vous pouvez voir ce résumé sur github
la source
J'ai eu la même réaction initiale. Moi aussi, j'étais frustré de voir comment la syntaxe et les objets changent si radicalement dans chaque version majeure.
Cependant, j'ai réalisé par expérience à quel point je finis toujours par subir les conséquences d'essayer de lutter contre le «changement», comme traiter avec des caractères multi-octets, ce qui est inévitable si vous regardez un public mondial.
J'ai donc décidé de reconnaître et de respecter les efforts déployés par les ingénieurs d'Apple et de faire ma part en comprenant leur état d'esprit lorsqu'ils ont proposé cette approche "horrible".
Au lieu de créer des extensions qui ne sont qu'une solution de contournement pour vous faciliter la vie (je ne dis pas qu'elles sont erronées ou coûteuses), pourquoi ne pas comprendre comment les chaînes sont maintenant conçues pour fonctionner.
Par exemple, j'avais ce code qui fonctionnait sur Swift 2.2:
et après avoir renoncé à essayer de faire fonctionner la même approche, par exemple en utilisant des sous-chaînes, j'ai finalement compris le concept de traiter les chaînes comme une collection bidirectionnelle pour laquelle je me suis retrouvé avec cette version du même code:
J'espère que cela contribue ...
la source
Même frustration, ça ne devrait pas être si difficile ...
J'ai compilé cet exemple d'obtention de positions pour des sous-chaînes à partir d'un texte plus grand:
renvoie ("Pourquoi", 0, 3) ("sous-chaînes", 26, 36) ("Swift3", 40, 46)
la source
Je suis nouveau dans Swift 3, mais en regardant la
String
syntaxe (index) pour l'analogie, je pense que l'index est comme un "pointeur" contraint à la chaîne et Int peut aider en tant qu'objet indépendant. En utilisant la syntaxe base + offset, nous pouvons alors obtenir le i-ème caractère de la chaîne avec le code ci-dessous:Pour une plage de caractères (index) de chaîne en utilisant la syntaxe de chaîne (plage), nous pouvons obtenir des caractères i-ème à f-ème avec le code ci-dessous:
Pour une sous-chaîne (plage) à partir d'une chaîne utilisant String.substring (plage), nous pouvons obtenir la sous-chaîne en utilisant le code ci-dessous:
Remarques:
Les i-ème et f-ème commencent par 0.
Pour f-ème, j'utilise offsetBY: f + 1, car la plage d'utilisation de l'abonnement .. <(opérateur semi-ouvert), n'inclut pas la f-ème position.
Bien sûr, doit inclure des erreurs de validation comme un index non valide.
la source
Swift 4+
Renvoie une sous-séquence des n premiers caractères ou la chaîne entière si la chaîne est plus courte. (inspiré par: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/take.html )
Exemple:
la source
Je pense assez mécaniquement. Voici les bases ...
Swift 4 Swift 5
Le résultat est une sous-chaîne, ce qui signifie qu'elle fait partie de la chaîne d'origine. Pour obtenir une chaîne séparée complète, utilisez par exemple
Voici ce que j'utilise:
la source
Swift 4
la source
J'ai créé une extension simple pour cela (Swift 3)
la source
Voici une implémentation plus générique:
Cette technique utilise toujours
index
pour respecter les normes de Swift et impliquer un personnage complet.Pour sous-chaîne à partir du 3e caractère:
J'ai utilisé du chameau
subString
pour indiquer qu'il renvoie unString
et non unSubstring
.la source
Sur la base de ce qui précède, je devais diviser une chaîne au niveau d'un caractère non imprimable en supprimant le caractère non imprimable. J'ai développé deux méthodes:
que j'ai rassemblé en utilisant certaines des réponses ci-dessus.
Parce qu'une chaîne est une collection, j'ai ensuite fait ce qui suit:
Ce qui pour moi était plus intuitif. Laquelle est la meilleure? Je n'ai aucun moyen de dire qu'ils travaillent tous les deux avec Swift 5
la source
Swift 4
"Sous-chaîne" ( https://developer.apple.com/documentation/swift/substring ):
Exemple d'extension de chaîne:
exemple d'utilisation de l'extension String:
la source
Swift 5
let desiredIndex: Int = 7 let substring = str[String.Index(encodedOffset: desiredIndex)...]
Cette variable de sous-chaîne vous donnera le résultat.
Simplement ici, Int est converti en Index et vous pouvez ensuite diviser les chaînes. À moins que vous n'obteniez des erreurs.
la source