Site de Jean-Michel RICHER

Maître de Conférences en Informatique à l'Université d'Angers

Ce site est en cours de reconstruction certains liens peuvent ne pas fonctionner ou certaines images peuvent ne pas s'afficher.


stacks

3. Chaînes de caractères

3.1. Chaînes en C et C++

3.1.1. Cas du langage C

En langage C, une chaîne de caractères est représentée par un tableau de caractères, sachant qu'un caractère est représenté par un octet. La fin de la chaîne est marquée par le caractère de fin de chaîne '\0', soit la valeur 0 codée sur 8 bits.

Les caractères sont entourés de guillemets simples (en anglais simple quotes) alors que les chaînes sont entourées de guillemets doubles (double quotes).

  • le caractère a minuscule est représenté par : 'a'
  • la chaîne bonjour par : "bonjour"

Certains caractères sont dits spéciaux comme la fin de ligne ou la tabulation et sont représentés par un caractère anti-slash suivi d'une lettre ou d'un chiffre :

  • caractère (ou marqueur) de fin de chaîne '\0'
  • retour arrière (backspace) '\b'
  • fin de ligne ou nouvelle ligne (new line ou Line Feed) '\n'
  • retour chariot (carriage return) '\r'
  • tabulation horizontale '\t'
  • tabulation verticale '\v'

La chaine "bonjour" est donc modélisée en mémoire par $8$ octets :

  • 7 caractères (ASCII/UTF8, voir ci-après) pour 'b', 'o', 'n', 'j', 'o', 'u', 'r'
  • le caractère de fin de chaîne '\0'

Le premier caractère 'b' se trouve à l'indice $0$ du tableau, et le dernier, '\0', se trouve à l'indice $7$.

Voici un petit programme qui montre comment manipuler les chaînes en C :

Afficher le code    ens/l1/bainf1/chaine_en_c.cpp
  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstring>
  4.  
  5. /* ------------------------------------------------------------------
  6.     QUOI
  7.        Fonction principale
  8.        
  9.    ------------------------------------------------------------------ */
  10. int main() {
  11.  
  12.     const char *chaine = "bon\tjour\n";
  13.    
  14.     // Affiche la chaine avec printf
  15.     printf("%s", chaine );
  16.     // Calcul et affichage de la longueur de la chaine grâce à strlen
  17.     unsigned int longueur = static_cast<unsigned int>(strlen( chaine ));
  18.     printf("longueur de la chaine: %u\n", longueur );
  19.    
  20.     // Affichage du premier caractère de la chaîne : 'b'
  21.     printf("premier caractère: %d %c\n", chaine[0],
  22.         chaine[0] );
  23.     // Affichage du dernier caractère de la chaîne, en l'occurrence '\n'
  24.     printf("dernier caractère: %d %c\n", chaine[longueur-1],
  25.         chaine[longueur-1] );
  26.    
  27.     return EXIT_SUCCESS;
  28. }
  29.  
  30.  

Le résultat au niveau du terminal donne :

bon    jour
longueur de la chaine: 9
premier caractère: 98 b
dernier caractère: 10 

3.1.2. Cas du langage C++

Afin de faciliter l'utilisation des chaînes en C++, la classe string a été introduite.

Elle dispose de méthodes comme size() qui retourne la longueur de la chaîne. On a également introduit la concaténation de chaînes grâce à la redéfinition de l'opérateur +.

Voici le même programme que précédemment mais en C++ avec la concaténation de chaînes :

Afficher le code    ens/l1/bainf1/chaine_en_cpp.cpp
  1. #include <iostream>
  2. #include <string>
  3.  
  4. /* ------------------------------------------------------------------
  5.     QUOI
  6.        Fonction principale
  7.        
  8.    ------------------------------------------------------------------ */
  9.  
  10. int main() {
  11.  
  12.     std::string chaine = "bon\tjour\n";
  13.    
  14.     // Affichage de la chaîne
  15.     std::cout << chaine << std::endl;
  16.     // Calcul de affichage de la longueur
  17.     size_t longueur = chaine.size();
  18.     std::cout << "longueur de la chaine: " << longueur << std::endl;
  19.    
  20.     // Affichage du premier caractère de la chaîne : 'b'
  21.     std::cout << "premier caractère: " << static_cast<int>(chaine[0])
  22.         << " " << chaine[0] << std::endl;
  23.     // Affichage du dernier caractère de la chaîne, en l'occurrence '\n' 
  24.     std::cout << "dernier caractère: " << static_cast<int>(chaine[longueur-1])
  25.         << " " << chaine[longueur-1] << std::endl;
  26.    
  27.     // Concaténation de chaînes
  28.     std::string chaine_1 = "bon";
  29.     std::string chaine_2 = "jour";
  30.    
  31.     std::string chaine_finale = chaine_1 + " " + chaine_2;
  32.     std::cout << chaine_finale << std::endl;
  33.    
  34.     return EXIT_SUCCESS;
  35. }
  36.  
  37.  

3.2. Représentation ASCII

L'ASCII pour American Standard Code for Information Interchange est une norme de codage des caractères apparue dans les années 1960. Elle est utilisée pour représenter les chaînes de caractères.

La première norme est l'ASCII 7 bits qui permet de représenter 128 caractères date du début des années 1960.

  • les caractères 0 à 31 sont des caractères de contrôle qui ne représentent pas un symbole mais permettent la mise en page de texte (comme le saut de page FF, le saut de ligne LF, le retour-chariot CR ou la tabulation horizontale HT), ou la transmission d'information pour les liaisons RS232 (port série) comme STX et ETX.
  • les plages de caractères de 32 à 47, 58 à 64, 91 à 96, 123 à 126 représentent des symboles tels que l'espace, les opérations arithmétiques, les signes de ponctuations (virgule, point, point-virgule, etc), les parenthèses, les crochets
  • les caractères 48 à 57 sont les chiffres
  • les lettres majuscules occupent la plage 65 à 90, alors que les lettres minuscules s'étendent de 97 à 122

L'ASCII a ensuite été étendu à 8 bits, soit 256 caractères, pour deux raisons :

  • les systèmes informatiques des années 1970 sont passés à la manipulation d'octets (8 bits)
  • on ne pouvait pas coder des textes dans d'autres langues, on a donc ajouté des caractères accentués du français ou d'autres langues (Norvégien, Allemand, Espagnol, etc)

On trouvera une description plus détaillée sur cette page Wikipedia.

On notera que la distance entre les majuscules et minuscules est de 32. Ainsi pour transformer 'A' en 'a', il suffit d'ajouter 32 au code ASCII de 'A'. Du point de vue du binaire, il suffit de positionner le bit 5 à 1, puisque $2^5 = 32$.

Voici un programme C++ qui transforme une chaîne en majuscule et minuscule.

Afficher le code    ens/l1/bainf1/chaines_min_maj.cpp
  1. #include <algorithm>
  2. #include <cctype>
  3. #include <iostream>
  4. #include <string>
  5.  
  6. int main() {
  7.     std::string chaine = "ABcdEFgh Ij";
  8.  
  9.     std::transform(chaine.begin(), chaine.end(), chaine.begin(), ::toupper);
  10.     std::cout << "Transformer en majuscules: " << chaine << std::endl;
  11.  
  12.     std::transform(chaine.begin(), chaine.end(), chaine.begin(), ::tolower);
  13.     std::cout << "Transformer en minuscules: " << chaine << std::endl;
  14.  
  15.     return EXIT_SUCCESS;
  16. }

3.2.1. Table des 256 caractères ASCII

Voici la table complète des 256 caractères de la norme ASCII (codes 0 à 255). Elle est subdivisée en deux tables de 128 caractères chacune, découpées en blocs de 32 caractères :

  • ASCII standard (codes 0 à 127, codés sur 7 bits) :
    • Codes 0 à 31 : caractères de contrôle non imprimables (comme \0 pour NUL, \n pour LF, \r pour CR, \t pour HT) ;
    • Codes 32 à 63 : espace (SP, code 32), ponctuation et les 10 chiffres décimaux (codes 48 à 57 pour '0' à '9') ;
    • Codes 64 à 95 : symbole '@', les 26 lettres majuscules (codes 65 à 90 pour 'A' à 'Z') et symboles ;
    • Codes 96 à 127 : accent grave '`', les 26 lettres minuscules (codes 97 à 122 pour 'a' à 'z'), symboles et DEL (code 127).
    Remarque : L'alignement en colonnes de 32 caractères permet d'observer immédiatement que la minuscule correspondante se situe sur la même ligne, exactement 32 positions plus loin (ex. 'A' = 65 et 'a' = 97).
  • ASCII étendu (codes 128 à 255, codés sur 8 bits) : Présenté ici selon la page de code standard CP437 (IBM PC / DOS, référence courante pour l'ASCII 8 bits), introduisant les lettres accentuées d'Europe occidentale (comme 'é' = 130, 'à' = 133, 'ç' = 135, 'ï' = 139), des symboles monétaires, des caractères semi-graphiques de tracés de boîtes et des symboles mathématiques et grecs.

Astuce : Vous pouvez survoler n'importe quel caractère pour afficher son code décimal, hexadécimal, binaire et sa description, ou cliquer dessus pour l'examiner.

Affichage :
Filtres de catégories : Tous Contrôle (0-31, 127) Chiffres (48-57) Majuscules (65-90) Minuscules (97-122) Symboles Étendu (128-255)
ASCII Standard (Codes 0 à 127 — 7 bits)
0 – 31 (Contrôle) 32 – 63 (Symboles / Chiffres) 64 – 95 (Majuscules) 96 – 127 (Minuscules)
DecHexCar DecHexCar DecHexCar DecHexCar
0 00 NUL 32 20 SP 64 40 @ 96 60 `
1 01 SOH 33 21 ! 65 41 A 97 61 a
2 02 STX 34 22 " 66 42 B 98 62 b
3 03 ETX 35 23 # 67 43 C 99 63 c
4 04 EOT 36 24 $ 68 44 D 100 64 d
5 05 ENQ 37 25 % 69 45 E 101 65 e
6 06 ACK 38 26 & 70 46 F 102 66 f
7 07 BEL 39 27 ' 71 47 G 103 67 g
8 08 BS 40 28 ( 72 48 H 104 68 h
9 09 HT 41 29 ) 73 49 I 105 69 i
10 0A LF 42 2A * 74 4A J 106 6A j
11 0B VT 43 2B + 75 4B K 107 6B k
12 0C FF 44 2C , 76 4C L 108 6C l
13 0D CR 45 2D - 77 4D M 109 6D m
14 0E SO 46 2E . 78 4E N 110 6E n
15 0F SI 47 2F / 79 4F O 111 6F o
16 10 DLE 48 30 0 80 50 P 112 70 p
17 11 DC1 49 31 1 81 51 Q 113 71 q
18 12 DC2 50 32 2 82 52 R 114 72 r
19 13 DC3 51 33 3 83 53 S 115 73 s
20 14 DC4 52 34 4 84 54 T 116 74 t
21 15 NAK 53 35 5 85 55 U 117 75 u
22 16 SYN 54 36 6 86 56 V 118 76 v
23 17 ETB 55 37 7 87 57 W 119 77 w
24 18 CAN 56 38 8 88 58 X 120 78 x
25 19 EM 57 39 9 89 59 Y 121 79 y
26 1A SUB 58 3A : 90 5A Z 122 7A z
27 1B ESC 59 3B ; 91 5B [ 123 7B {
28 1C FS 60 3C < 92 5C \ 124 7C |
29 1D GS 61 3D = 93 5D ] 125 7D }
30 1E RS 62 3E > 94 5E ^ 126 7E ~
31 1F US 63 3F ? 95 5F _ 127 7F DEL
ASCII Étendu (Codes 128 à 255 — 8 bits — Page CP437)
128 – 159 (Accents / Devises) 160 – 191 (Accents / Symboles) 192 – 223 (Cadres / Boîtes) 224 – 255 (Maths / Grecs)
DecHexCar DecHexCar DecHexCar DecHexCar
128 80 Ç 160 A0 á 192 C0 └ 224 E0 α
129 81 ü 161 A1 í 193 C1 ┴ 225 E1 ß
130 82 é 162 A2 ó 194 C2 ┬ 226 E2 Γ
131 83 â 163 A3 ú 195 C3 ├ 227 E3 π
132 84 ä 164 A4 ñ 196 C4 ─ 228 E4 Σ
133 85 à 165 A5 Ñ 197 C5 ┼ 229 E5 σ
134 86 å 166 A6 ª 198 C6 ╞ 230 E6 µ
135 87 ç 167 A7 º 199 C7 ╟ 231 E7 τ
136 88 ê 168 A8 ¿ 200 C8 ╚ 232 E8 Φ
137 89 ë 169 A9 ⌐ 201 C9 ╔ 233 E9 Θ
138 8A è 170 AA ¬ 202 CA ╩ 234 EA Ω
139 8B ï 171 AB ½ 203 CB ╦ 235 EB δ
140 8C î 172 AC ¼ 204 CC ╠ 236 EC ∞
141 8D ì 173 AD ¡ 205 CD ═ 237 ED φ
142 8E Ä 174 AE « 206 CE ╬ 238 EE ε
143 8F Å 175 AF » 207 CF ╧ 239 EF ∩
144 90 É 176 B0 ░ 208 D0 ╨ 240 F0 ≡
145 91 æ 177 B1 ▒ 209 D1 ╤ 241 F1 ±
146 92 Æ 178 B2 ▓ 210 D2 ╥ 242 F2 ≥
147 93 ô 179 B3 │ 211 D3 ╙ 243 F3 ≤
148 94 ö 180 B4 ┤ 212 D4 ╘ 244 F4 ⌠
149 95 ò 181 B5 ╡ 213 D5 ╒ 245 F5 ⌡
150 96 û 182 B6 ╢ 214 D6 ╓ 246 F6 ÷
151 97 ù 183 B7 ╖ 215 D7 ╫ 247 F7 ≈
152 98 ÿ 184 B8 ╕ 216 D8 ╪ 248 F8 °
153 99 Ö 185 B9 ╣ 217 D9 ┘ 249 F9 ∙
154 9A Ü 186 BA ║ 218 DA ┌ 250 FA ·
155 9B ¢ 187 BB ╗ 219 DB █ 251 FB √
156 9C £ 188 BC ╝ 220 DC ▄ 252 FC ⁿ
157 9D ¥ 189 BD ╜ 221 DD ▌ 253 FD ²
158 9E ₧ 190 BE ╛ 222 DE ▐ 254 FE ■
159 9F ƒ 191 BF ┐ 223 DF ▀ 255 FF NBSP

3.3. Encodage Windows

Les encodages de la famille Windows-125x (allant de 1250 à 1258) sont une série de pages de codes (jeux de caractères) codées sur 8 bits, créées par Microsoft pour permettre à ses systèmes d'exploitation d'afficher différents alphabets régionaux avant l'adoption généralisée d'Unicode.

Chaque encodage de cette famille partage la même structure de base :

  • Compatibilité ASCII : Les 128 premiers caractères (de 0 à 127) sont strictement identiques à l'ASCII standard (lettres non accentuées, chiffres, ponctuation de base).
  • Spécialisation régionale : Les 128 caractères suivants (de 128 à 255) sont remplacés pour s'adapter à une région linguistique ou à un alphabet spécifique.
  • Différence avec l'ISO-8859 : Contrairement aux normes internationales ISO-8859 (comme l'ISO-8859-1) qui réservent la plage 128-159 à des caractères de contrôle invisibles, Microsoft a exploité cet espace pour ajouter des caractères typographiques utiles tels que le symbole de l'euro (€), les guillemets (« »), le signe pour mille (‰) ou la ligature œ.

Voici la répartition linguistique des encodages de cette série :

  • Windows-1250 : Europe centrale et de l'Est (Polonais, Tchèque, Slovaque, Hongrois, Roumain, etc.).
  • Windows-1251 : Alphabets cyrilliques (Russe, Bulgare, Serbe, Ukrainien, etc.).
  • Windows-1252 : Europe occidentale (Français, Anglais, Allemand, Espagnol, etc.). C'est le plus célèbre et le plus utilisé dans nos régions, très proche de l'ISO-8859-1 (Latin-1).
  • Windows-1253 : Alphabet grec.
  • Windows-1254 : Turc.
  • Windows-1255 : Alphabet hébreu.
  • Windows-1256 : Alphabet arabe.
  • Windows-1257 : Langues baltes (Estonien, Letton, Lituanien).
  • Windows-1258 : Vietnamien (utilise un système combinant des lettres de base et des tons séparés pour s'adapter à la limite des 8 bits)

Il est résulte des problèmes d'affichage lorsque l'on s'attend à trouver un encodage 1250 alors que le fichier est codé dans une autre variante. Ou lorsque l'on convertit de Windows vers UTF.

3.4. Unicode et représentation UTF

Le problème de l'ASCII est qu'il ne permet de coder que 256 caractères différents ce qui est insuffisant au regard de toutes les langues qui existent ainsi que des symboles (mathématiques, physique, chimie) que l'on peut utiliser dans l'écriture courante.

Le standard Unicode dans sa version 17 (Septembre 2025) permet de coder $159\_ 801$ caractères, couvrant plus de 150 écritures.

On pourra trouver l'équivalence des premiers caractères sur cette page.

Pour simplifier :

  • Unicode décrit les caractères
  • UTF-8/16/32 indique comment coder les caractères Unicode en utilisant un ou plusieurs octets

3.4.1. Représentation UTF-8 et UTF-32

L'encodage par octet, UTF-8 Universal (Character Set) Transformation Format), a été conçu pour coder des chaînes à la manière de ce que l'on peut faire avec l'ASCII et est très utilisé par le protocole HTML et les éditeurs de texte. Il existe trois codages UTF dits UTF-8, 16 ou 32.

Le standard Unicode définit des ensembles de caractères et chaque caractère est identifié par son point de code qui est en fait un indice entier. Par exemple le symbole € a pour point de code la valeur 8364 soit U+20AC en hexadécimal dans le standard Unicode.

Sous Linux pour obtenir ce symbole s'il n'est pas disponible sur le clavier il faut :

  • maintenir enfoncées les touches Ctrl + Shift + U
  • relacher puis taper 2 0 A C
  • en enfin appuyer sur Enter

L'UTF permet de transformer le point de code des caractères Unicode en une série d'octets.

L'intérêt majeur de l'UTF-8 est qu'il est rétro-compatible avec l'ASCII 7 bits :

  • Les 127 premiers caractères de l'ASCII 7 bits ont les mêmes valeurs en UTF-8 et sont donc codés sur un octet
  • pour coder les caractères de valeurs comprises entre 128 et 2047 on utilise deux octets
  • puis trois octets pour coder les caractères de valeurs comprises entre 2048 et 65535
  • Enfin, on utilise quatre octets pour les caractères de valeurs supérieures à 65535

En UTF-32 chaque caractère est codé par une valeur 32 bits ce qui prend plus de place que l'UTF-8. Comme on peut le voir ci-dessous.

Imaginons que notre fichier contienne 5 lettres puis un passage à la ligne (↵) :


aéïou↵

Voici les différents codages obtenus grâce aux utilitaires linux iconv, konwert et hexdump pour l'affichage. Il est à noter que iconv ne parvient pas à réaliser la transformation vers l'ASCII semble t-il, je l'ai donc réalisée moi-même.

Les codages sont donnés en octets en base 16 :

ASCII
00000000  61 82 8b 6f 75 0a                                     |aeiou.|
00000006

UNICODE
00000000  ff fe |61 00| e9 00| ef 00|  6f 00| 75 00| 0a 00      |..a.....o.u...|
0000000e

UTF8
00000000  61| c3 a9| c3 af| 6f| 75| 0a                          |a....ou.|
00000008

UTF-16
00000000  ff fe| 61 00| e9 00| ef 00|  6f 00| 75 00| 0a 00      |..a.....o.u...|
0000000e

UTF-32
00000000  ff fe 00 00| 61 00 00 00|  e9 00 00 00| ef 00 00 00|  |....a...........|
00000010  6f 00 00 00| 75 00 00 00|  0a 00 00 00|               |o...u.......|
0000001c

La suite de valeurs FF FE en UTF-16 bits et FF FE 00 00 en UTF-32 indique l'ordre de lecture des caractères, ici cela signifie qu'il faut commencer par la première valeur trouvée. C'est ce que l'on appelle le BOM pour Byte Order Mark (voir cette page). On notera qu'en UTF-8 elle utilise trois valeurs : EF BB BF

Dans le cas de l'UTF-32, la séquence d'octets 61 00 00 00 doit donc être considérée comme la valeur hexadécimale $00\_00\_00\_61_{16} = 97_{10} = $ 'a'.

3.4.2. Mécanique de l'encodage UTF-8 (au-delà de 127)

Le codage UTF-8 repose sur un système de masques binaires à taille variable. Au-delà du point de code 127 (U+007F, fin de l'ASCII strict), l'UTF-8 abandonne le format sur un seul octet pour utiliser des séquences de 2 à 4 octets.

La mécanique consiste à convertir le point de code Unicode en binaire, puis à distribuer ces bits à l'intérieur d'un modèle prédéfini d'octets.

Les gabarits d'encodage UTF-8

Le choix du nombre d'octets dépend directement de la valeur du point de code Unicode :

  • 2 octets : de U+0080 (128) à U+07FF (2047) -- (8 à 11 bits). Masque : 110xxxxx 10xxxxxx
  • 3 octets : de U+0800 (2048) à U+FFFF (65_535) -- (12 à 16 bits). Masque : 1110xxxx 10xxxxxx 10xxxxxx
  • 4 octets : de U+10000 (65_536) à U+10FFFF (1_114_111) (17 à 21 bits). Masque : 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

Règles de lecture des octets :

  • l'octet de tête (Lead byte) : indique le nombre de bits consécutifs à 1 au tout début de cet octet indique la longueur totale de la séquence (ex: 110... = 2 octets).
  • les octets de suite (Continuation bytes) : commencent tous obligatoirement par la séquence 10, c'est cette caractéristique d'auto-synchronisation qui permet à un programme de savoir immédiatement s'il lit le milieu d'un caractère.
  • les bits de données (x) : sont les emplacements libres où l'on vient insérer la valeur binaire du point de code Unicode, en remplissant de droite à gauche.

Exemple de conversion pas à pas : Le symbole Euro (€)

Le symbole de l'Euro a pour point de code Unicode U+20AC.

1. Conversion du point de code en binaire
La valeur hexadécimale 20AC ($8364_{10}$) se traduit en binaire par 16 bits :
0010 0000 1010 1100

2. Sélection du masque
La valeur U+20AC se situe dans la plage U+0800 à U+FFFF. Il faut donc utiliser un encodage sur 3 octets.
Le masque à remplir est : 1110xxxx 10xxxxxx 10xxxxxx

3. Découpage des bits du point de code
On prend nos 16 bits binaires et on les tronçonne, en partant de la droite, pour correspondre aux blocs de x du masque (6 bits, puis 6 bits, puis 4 bits) :

0010 0000 1010 1100

  • Bloc 3 (droite) : 101100
  • Bloc 2 (milieu) : 000010
  • Bloc 1 (gauche) : 0010

4. Insertion dans le masque UTF-8
On insère ces blocs à la place des x :

  • Octet 1 : 1110 suivi de 0010 → 11100010 (en hexadécimal : E2)
  • Octet 2 : 10 suivi de 000010 → 10000010 (en hexadécimal : 82)
  • Octet 3 : 10 suivi de 101100 → 10101100 (en hexadécimal : AC)

En mémoire, le caractère Unicode U+20AC sera donc stocké avec la séquence d'octets E2 82 AC.

Exercice 3.1

Coder la chaîne suivante "29, éÄ!"

  • en ASCII
  • en UTF-8

Exercice 3.2

Chiffrer la chaine "a l'aide" en remplaçant chaque lettre par la suivante et les signes de ponctuation ou les espaces par un '.'. Si on doit chiffrer la lettre 'z', on recommence à partir de 'a'. Toute les lettres doivent apparaître sans accent.

Exercice 3.3

Déchiffrer la chaine "KPHQTOG.OC.VKSWG" en remplaçant chaque lettre par la lettre qui se trouve à deux positions précédentes. Dans ce cas 'B' se transforme en 'Z' et 'A' en 'Y'.

Exercice 3.4

Combien d'octets sont nécessaires pour coder une chaîne UTF-8 contenant :

  • 10 caractères avec un point de code inférieur à 128
  • 10 caractères avec un point de code compris entre 128 et 2047.

Exercice 3.5

Combien d'octets sont nécessaires pour coder une chaîne UTF-32 contenant :

  • 10 caractères avec un point de code inférieur à 128
  • 10 caractères avec un point de code compris entre 128 et 2047.

Exercice 3.6

Codez le caractère chinois unicode U+6211 (en base 16) 我 (wǒ = moi, je) en UTF-8

La réponse doit être $E6\_88\_91_{16}$ en hexadécimal.