Introduction : Pourquoi la « longueur d’une chaîne » n’est-elle pas qu’un simple chiffre ?
\n\nImaginez que vous développez une application pour iOS. L’utilisateur saisit son nom dans un champ de texte. Simple, non ? Et si le nom contient des emojis, des signes diacritiques (par exemple, « café ») ou des idéogrammes ? Soudain, la tâche simple « obtenir la longueur d’une chaîne » se transforme en enquête avec des éléments Unicode.
\n\nEn Swift, travailler avec les chaînes ne se résume pas à compter des caractères. C’est un voyage dans le monde des clusters de graphèmes, des scalaires Unicode et de l’héritage d’Objective-C (oui, oui, NSString est toujours avec nous). Si vous commencez tout juste à apprendre Swift ou si vous venez d’autres langages, cet article est pour vous. Nous allons voir comment déterminer correctement la longueur d’une chaîne, quels pièges vous attendent et quand utiliser count ou NSString.
Ce contenu est basé sur une question populaire réelle de Stack Overflow. Des milliers de développeurs ont trébuché sur ce sujet. Ne répétons pas leurs erreurs. C’est parti !
\n\n\n\n
1. Les bases : la propriété count de String
\n\nLa façon la plus évidente d’obtenir la longueur d’une chaîne en Swift est d’utiliser la propriété count. Elle renvoie le nombre de « caractères » (Character) dans la chaîne. Mais qu’est-ce qu’un caractère pour Swift ?
let greeting = "Привет, мир!"\nprint(greeting.count) // 12 (y compris l’espace et le point d’exclamation)\n\nTout fonctionne comme prévu. Mais compliquons la tâche :
\n\nlet emojiString = "👨👩👧👦"\nprint(emojiString.count) // 1 (!!!)\n\nUn ? Sérieusement ? Et visuellement, c’est toute une famille de quatre personnes. Où est le piège ?
\n\nLa réponse réside dans la façon dont Swift traite les chaînes. count ne compte ni les octets ni les caractères Unicode individuels, mais les clusters de graphèmes étendus (extended grapheme clusters). Il s’agit d’une séquence d’un ou plusieurs scalaires Unicode perçus par l’utilisateur comme un seul caractère. L’emoji « famille » est composé de plusieurs parties, mais Swift le compte comme un seul caractère, car c’est ainsi que l’humain le voit.
Ce comportement n’est pas un bug, mais une fonctionnalité. Swift est conçu pour l’internationalisation. Si count comptait chaque scalaire Unicode, la chaîne « café » (avec un seul caractère é) pourrait donner un résultat différent selon la façon dont é est encodé : comme un seul caractère U+00E9 ou comme une combinaison e + accent (U+0065 + U+0301).
let cafe1 = "café" // é comme un seul caractère\nlet cafe2 = "cafe\\u{0301}" // e + accent\nprint(cafe1.count) // 4\nprint(cafe2.count) // 4 (bien que la chaîne contienne 5 scalaires)\n\nSwift compte les deux variantes comme 4 caractères, car l’utilisateur voit « café » avec 4 lettres. C’est la magie des clusters de graphèmes.
\n\n\n\n
2. Approche alternative : NSString et la propriété length
\n\nParfois, vous avez besoin non pas du nombre « humain » de caractères, mais du nombre d’unités de codage UTF-16. Par exemple, lorsque vous travaillez avec des API obsolètes, Core Text ou lors du transfert de données dans des formats qui attendent une longueur en UTF-16 (comme certains protocoles réseau).
\n\nC’est là qu’intervient NSString, la bonne vieille classe d’Objective-C. Les chaînes Swift sont automatiquement pontées (bridge) vers NSString, vous pouvez donc utiliser sa propriété length :
let swiftString = "👨👩👧👦"\nlet nsString = swiftString as NSString\nprint(nsString.length) // 11 (nombre d’unités UTF-16)\n\nPourquoi 11 ? Parce que l’emoji composé « famille » occupe 11 unités en UTF-16 (chaque composant est encodé par une paire de substitution ou un caractère individuel). Si vous travaillez avec du texte qui sera traité par d’anciennes bibliothèques C ou des API attendant NSString, utilisez length. Mais rappelez-vous : ce n’est pas le nombre de caractères que l’utilisateur voit.
Autre nuance : NSString ne tient pas compte des clusters de graphèmes. Pour la chaîne « café » (deuxième variante), length renverra 5, alors que count renvoie 4. Conclusion : choisissez la méth