Les chaînes de caractère en Swift

Dans ce cours nous allons traiter d’un des types les plus utiliser en Swift (et dans la majorité des langages) : les chaînes de caractères (strings en anglais). Pour ce faire nous vous proposons un traduction de la documentation officielle d’Apple. Tout d’abord une chaîne de caractère est une série de caractère tel que « Hello World » ou « Swift Tuto ». Les chaînes de caractère sont représentées par le type String en Swift. Une String est représenté en interne par une collection de caractère que sont de type Character.


Les types String et Character respectent le format unicode et fournissent un moyen rapide et simple pour travailler avec les textes dans votre code. La syntaxe pour créer et manipuler une chaîne de caractère est très légère et lisible grâce, avec notamment, une syntaxe littérale de chaîne qui est similaire à C. La concaténation se fait en additionnant deux chaînes avec l’opérateur +, et la mutabilité d’une chaîne est géré la définissant soir comme une constante soit comme une variable, comme toute autre valeur en Swift. Vous pouvez également utiliser les String pour insérer des constantes, des variables, des littéraux et des expressions dans des chaînes plus longues, dans un processus connu en tant qu’interpolation de chaîne. Cela permet de créer des chaînes de caractère de manière beaucoup pour simple pour l’affichage, le stockage et l’impression.

Malgré cette simplicité de syntaxe, l’implémentation des String en Swift est moderne et rapide. Chaque chaîne est composée de caractères Unicode indépendant, et fournit un support pour accéder à ces caractères dans les différentes représentations Unicode.

Les littéraux de String

Vous pouvez inclure des String prédéfinis dans votre code comme des littéraux de chaîne. Un littéral de chaîne est une séquence fixe de caractère contextuel entourée par une pair de guillemet (""). Utilisez un littéral de chaîne comme une valeur initiale d’une variable ou d’une constante :

let uneChaine = "Une valeur littérale de chaine"

Vous pouvez noter ici que Swift peut inférer le type String pour la contante uneChaine car elle est initialisée avec un littéral de chaîne.

Initialiser un chaîne vide

Pour créer une String vide comme chaîne initiale pour construire une chaîne plus longue par la suite, vous pouvez soit assigner un littéral vide à une variable ou alors initialiser une nouvelle chaîne avec la syntaxe habituelle d’initialisation :

// 2 chaîne équivalente
var chaineVide      = "" // littéral vide
var autreChaineVide = String() // syntaxe initializer

if chaineVide.isEmpty {
  print("La chaîne est vide")
}
// Affiche : "La chaîne est vide"

Mutabilité des chaînes

Vous indiquez qu’une chaîne peut être modifiée ou non en la définissant comme variable ou comme constante :

var chaineModifiable = "Chien"
chaineModifiable     += " et laisse"
// chaineModifiable est maintenant "Chien et laisse"

let chaineConstante = "Pierre"
chaineConstante     += " et un autre Pierre"
// Ceci produit une erreur à la compilation car une constante ne peut pas être modifié

Les String sont des types valeur

Il est important de noter que les String sont de type valeur. Cela veut dire que lorsque les chaînes sont passées en argument d’une fonction à une autre ou enregistrer dans des variables ou des contantes elles sont copiées. Donc si vous modifier la chaîne dans la méthode, la modification ne sera pas répercutée sur la variable initiale.

Du coté du compilateur, Swift optimise l’utilisation des chaînes de manière à ce qu’elles soient copiées uniquement quand cela est vraiment nécéssaire. Cela veut dire que vous avez toujours des très bonnes performance quand vous utiliser les String, même en tant que type valeur.

Travailler avec les caractères

Vous pouvez accéder aux valeurs des Character individuellement dans une String en itérant au travers de ses caractères avec une boucle for-in :

for character in "Chien ! 🐶".characters {
  print(character)
}
// C
// h
// i
// e
// n
//
// !
//
// 🐶

D’une autre manière vous pouvez aussi créer une collection de Character indépendamment d’une chaîne :

let chatCharacters: [Character] = ["C", "h", "a", "t", " ", "!", " ", "🐱"]

Puis construire une String en passant cette collection de Character dans l’initialiser :

let chatString = String(chatCharacters)
print(chatString)
// Affiche "Chat ! 🐱"

L’interpolation de chaîne

L’interpolation de chaîne est une manière de construire de nouvelle String en utilisant un mélange de constante, variable, littéral et d’expression incluant leurs valeurs dans la littéral. Chaque élément que vous insérez dans la chaîne est enveloppé dans une pair de parenthèse préfixé d’un anti-slash :

let multiplier = 3
let message    = "\(multiplier) fois 2.5 est \(Double(multiplier) * 2.5)"
// message est "3 fois 2.5 est 7.5"

Dans l’example du dessus la valeur du multiplier est insérer dans le littéral comme \(multiplier). Cet espace réservé est remplacé par la valeur du multiplier quand l’interpolation de chaîne est évaluée pour créer la chaîne final.

La valeur du multiplier fait aussi partie d’une expression pour large ensuite dans la chaîne. Cette expression calcule la valeur Double(multiplier) * 2.5 et insère le résultat (7.5) dans la chaîne.

Unicode

Unicode est une norme internationale pour encoder, représenter et pour traiter du text dans différent système d’écriture. Il permet de représenter presque tout les caractères de tout les langages dans une forme standardisée et de les lire et écrire depuis une source externe comme une fichier de texte ou un page web. En Swift, les String et Character sont entièrement compatible avec cette norme comme décrit dans cette section.

Code scalaires

Le type String en Swift est construit à partir de scalaire unicode. Un code scalaire est un nombre unique de 21-bit pour un caractère ou un modifieur, comme U+0061 pour LATIN SMALL LETTER A (« a ») ou U+1F425 for FRONT-FACING BABY CHICK (« 🐥 »).

À noter qu’un code scalaire en Unicode est un nombre entre U+0000 et U+D7FF inclus ou entre U+E000 et U+10FFFF inclus.

Caractères spéciaux dans les littéraux de chaîne

Les littéraux de chaîne peuvent inclure les caractères spéciaux suivant :

  • Les caractères spéciaux « échappés » : \0 (caractère null), \\ (backslash), \t (tab horizontal), \n (retour à la line), \r (retour charriot), \ » (guillemet) and \’ (apostrophe)
  • Un code scalaire Unicode arbitraire écrit comme \u{n}, où n est un entier hexadécimal correspondant à un code Unicode valide.

L’example ci-dessous montre 4 example d’utilisation de caractère spéciaux dans un littéral :

let wiseWords      = "\"Imagination is more important than knowledge\" - Einstein"
// "Imagination is more important than knowledge" - Einstein
let dollarSign     = "\u{24}" // $, Unicode scalar U+0024
let blackHeart     = "\u{2665}" // ♥, Unicode scalar U+2665
let sparklingHeart = "\u{1F496}" // 💖, Unicode scalar U+1F496

Groupes de graphème étendus

Toute instance d’un type Character en Swift représente un seul groupe de graphème. Un groupe étendu de graphème est une séquence d’un ou plusieurs code scalaire Unicode qui, combiné, produise un caractère lisible pour les humains.

Par example la lettre é peut être représenté par un seul scalaire : U+00E9 (LATIN SMALL LETTER E WITH ACUTE). Mais la même lettre peut aussi être représenté par une pair de scalaire : la lettre e U+0065 (LATIN SMALL LETTER E) suivi de l’accent U+0301 (COMBINING ACUTE ACCENT). le scalaire COMBINING ACUTE ACCENT est graphiquement appliqué à l’élément qui le précède, transformant la lettre e en un é.

Dans les deux cas la lettre é est représenté comme une seule instance de Character en Swift qui représente le groupe de graphème. Dans le premier cas, le groupe contient un seul scalaire, dans le deuxième cas c’est un groupe de deux scalaires :

let eAcute: Character         = "\u{E9}" // é
let combinedEAcute: Character = "\u{65}\u{301}" // e suivit de by ́
// eAcute est é, combinedEAcute est é

Les groupe de graphème étendus sont un moyen flexible de représenter plusieurs enchainements de caractère en une seule valeur. Par example les syllabes hangûles de l’alphabet Koréen peuvent être représenté soit comme une séquence pré-composée ou décomposée. Chacune de ces représentations forment un seul Character en Swift :

let precomposed: Character = "\u{D55C}" // 한
let decomposed: Character  = "\u{1112}\u{1161}\u{11AB}" // ᄒ, ᅡ, ᆫ
// pré-composé is 한, décomposé is 한

Compter les caractères

Pour retrouver le nombre de caractère dans une chaîne il suffit d’utiliser la propriété count de la propriété characters de String :

let unusualMenagerie = "Koala 🐨, Snail 🐌, Penguin 🐧, Dromedary 🐪"
print("unusualMenagerie a \(unusualMenagerie.characters.count) caractères")
// prints "unusualMenagerie a 40 caractères"

Il faut noter qu’en Swift l’utilisation de groupe de graphème pour les valeurs des Character dans la concaténation et la modification de chaîne peut n’avoir aucun impact sur le nombre de caractère.

Par example, si vous créez une nouvelle String avec le mot cafe à 4 caractères et qu’ensuite vous concaténez un scalaire Unicode U+0301 (COMBINING ACUTE ACCENT) à la fin de la chaîne le résultat sera toujours de 4 caractères :

var word = "cafe"
print("le nombre caractère dans \(word) est de \(word.characters.count)")
// Affiche : "le nombre caractère dans cafe est de 4"

word += "\u{301}" // COMBINING ACUTE ACCENT, U+0301
print("le nombre caractère dans \(word) est de \(word.characters.count)")
// Affiche : "le nombre caractère dans café est de 4"

Modifier une chaîne de caractère

Vous pouvez accéder et modifier une chaîne au travers de ces méthodes et propriétés ou en utilisant la syntaxe de subscript.

Indices de chaîne

Chaque String a un type d’index associé, String.Index, qui correspond à la position de chaque Character dans la chaîne.

Comme mentionné ci-dessus, différents caractères peuvent nécessiter différentes quantités de mémoire pour le stockage, donc afin de déterminer la position d’un caractère particulier, vous devez itérer au travers de chaque scalaire Unicode du début ou à la fin de cette chaîne. C’est pour cette raison que les chaînes en Swift ne peuvent pas être indexés en utilisant des valeurs entières.

Il faut utilisez la propriété startIndex pour accéder à la position du premier Character d’une String. La propriété endIndex représente la position du dernier Character. Si une chaîne est vide startIndex et endIndex sont égaux.

Une String.Index peut accéder immédiatement à son prédécesseur en appelant la méthode predecessor() et atteindre le successeur en appelant la méthode successor(). N’importe quel index dans une chaîne peut être accéder depuis n’importe quel autre index en chainant les méthodes ensemble ou en utilisant la méthode advancedBy(_:).

Vous pouvez utiliser le subscripting pour accéder au Character à un index particulier.

let greeting = "Guten Tag!"
greeting[greeting.startIndex]
// G

greeting[greeting.endIndex.predecessor()]
// !

greeting[greeting.startIndex.successor()]
// u

let index = greeting.startIndex.advancedBy(7)
greeting[index]
// a

Accéder à un Character avec un index en dehors des limites de la chaîne va lever une erreur à l’execution :

greeting[greeting.endIndex] // error
greeting.endIndex.successor() // error

On peut utiliser la propriété indices des Character pour créer une place contenant tout les indexes utilisé pour accéder aux caractères individuellement :

for index in greeting.characters.indices {
  print("\(greeting[index]) ", terminator: "")
}
// Affiche : "G u t e n T a g !"

Ajout et Suppression

Pour ajouter un caractère dans une chaîne à un index donné, il faut utiliser la méthode insert(_:atIndex:) :

var welcome = "hello"
welcome.insert("!", atIndex: welcome.endIndex)
// welcome est égale à "hello!"

Pour ajouter le contenu d’une autre chaîne a un index donné, la méthode insertContentsOf(_:at:) est là pour ça :

welcome.insertContentsOf(" there".characters, at: welcome.endIndex.predecessor())
// welcome est égale à "hello there!"

Pour supprimer un caractère d’une chaîne à un index donné, il faut utiliser la méthode removeAtIndex(_:) :

welcome.removeAtIndex(welcome.endIndex.predecessor())
// welcome est égale à "hello there"

Pour supprimer une sous-chaîne dans une plage donné, utilisez la méthode removeRange(_:) :

let range = welcome.endIndex.advancedBy(-6)..<welcome.endIndex
welcome.removeRange(range)
// welcome est égale à "hello"

Comparaison de String

Swift fournit 3 manières de comparer des valeurs textuels : l’égalité des String et des Characters, l’égalité des préfix, et l’égalité des suffix.

Égalité des String et des Character

L’égalité des String et des Character est vérifiée avec les opérateurs == (equal) et != (not equal) :

let quotation     = "Nous somme pareil"
let sameQuotation = "Nous somme pareil"

if quotation == sameQuotation {
  print("Ces 2 chaînes sont considérées comme égales")
}
// Affiche "Ces 2 chaînes sont considérées comme égales"

2 chaînes (ou caractères) sont considérées comme égales si leurs groupes de graphème étendus sont canoniquement équivalent. Les groupes de graphème étendus sont canoniquement équivalent si ils ont la même signification et apparence, même si ils sont composés de différent scalaire Unicode :

// "Voulez-vous un café?" utilisant LATIN SMALL LETTER E WITH ACUTE
let eAcuteQuestion = "Voulez-vous un caf\u{E9}?"

// "Voulez-vous un café?" utilisant LATIN SMALL LETTER E et COMBINING ACUTE ACCENT
let combinedEAcuteQuestion = "Voulez-vous un caf\u{65}\u{301}?"

if eAcuteQuestion == combinedEAcuteQuestion {
  print("Ces 2 chaînes sont considérées comme égales")
}
// Affiche "Ces 2 chaînes sont considérées comme égales"

Egalité des préfix et suffix

Pour vérifier si une chaîne a un préfix ou un suffix particulier, il faut appeler les méthodes hasPrefix(_:) et hasSuffix(_:), toute les 2 prenant un seul argument de type String et retournant un booléen.

L’example au dessous considère une liste de chaîne représentant la scene de la location représente les lieux des deux premiers acte de Roméo et Juliette de Shakespeare :

let romeoAndJuliet = [
  "Act 1 Scene 1: Verona, A public place",
  "Act 1 Scene 2: Capulet's mansion",
  "Act 1 Scene 3: A room in Capulet's mansion",
  "Act 1 Scene 4: A street outside Capulet's mansion",
  "Act 1 Scene 5: The Great Hall in Capulet's mansion",
  "Act 2 Scene 1: Outside Capulet's mansion",
  "Act 2 Scene 2: Capulet's orchard",
  "Act 2 Scene 3: Outside Friar Lawrence's cell",
  "Act 2 Scene 4: A street in Verona",
  "Act 2 Scene 5: Capulet's mansion",
  "Act 2 Scene 6: Friar Lawrence's cell"
]

Vous pouvez utiliser la méthode hasPrefix(_:) avec la liste romeoAndJuliet pour compter le nombre de scene dans l’acte 1 qui est joué :

var act1SceneCount = 0

for scene in romeoAndJuliet {
  if scene.hasPrefix("Act 1 ") {
    ++act1SceneCount
  }
}
print("Il y a \(act1SceneCount) scènes dans l'acte 1")
// Affiche "Il y a 5 scènes dans l'acte 1"

De la même manière la méthode hasSuffix(_:) permet de faire la même chose en comparant la fin de chaîne.

1 Etoile2 Etoiles3 Etoiles4 Etoiles5 Etoiles (3 votes, average: 4,67 out of 5)
Loading...
Share on FacebookShare on Google+Tweet about this on TwitterShare on LinkedInPin on PinterestShare on RedditDigg this

Aucun commentaire

Time limit is exhausted. Please reload CAPTCHA.