UTF-8 : le standard sur Internet

Si vous parvenez à lire un site Internet en anglais ou un e-mail en japonais, c’est que maîtrisez ces langues, mais sans le savoir, vous êtes également témoin de l’hégémonie d’UTF-8. « UTF-8 » est l’abréviation de « 8-Bit UCS Transformation Format » et désigne le codage de caractères le plus largement répandu sur le World Wide Web. Le standard international Unicode comprend l’intégralité des caractères et éléments textuels de toutes les langues du monde (ou presque) pour le traitement informatique. UTF-8 joue un rôle de premier plan dans le jeu de caractères Unicode.

Développement du codage UTF-8

UTF-8 est un codage de caractères. Il attribue à chaque caractère Unicode existant une séquence de bits précise que l’on peut également lire comme un nombre binaire. Cela signifie qu’UTF-8 attribue un nombre binaire fixe à l’ensemble des lettres, chiffres et symboles d’une quantité toujours plus importante de langues. Certaines organisations internationales, qui accordent une grande importance aux normes Internet et souhaitent les établir, travaillent à faire d’UTF-8 un acteur incontournable du codage. W3C mais aussi l’Internet Engineering Task Force y travaillent notamment d’arrache-pied, non sans résultat puisque, depuis 2009, la plupart des sites Internet du monde utilisent le codage UTF-8. D’après une expertise de W3Techs, en mars 2018, 90,9 % des sites Internet existants utilisaient ce codage de caractère.

Problèmes avant l’introduction d’UTF-8

Différentes régions du monde disposant de langues et de systèmes d’écriture apparentés ont développé leurs propres standards de codage afin de répondre à des exigences différentes. L’espace anglophone, par exemple, se satisfaisait du codage ASCII dont la structure permet d’attribuer 128 caractères à une chaîne de caractères lisible par ordinateur. Les polices asiatiques ou l’alphabet cyrillique disposent toutefois de caractères plus singuliers et les voyelles infléchies allemandes (par exemple ä) sont également absentes de l’ASCII. Par ailleurs, les chaînes de caractères attribuées par différents codages pouvaient se chevaucher. On pouvait par exemple se retrouver dans des situations où un document publié en russe n’était pas affiché avec des lettres cyrilliques sur un ordinateur américain, mais avec les lettres latines attribuées conformément au système de cet ordinateur. La cacographie qui en résultait compliquait sensiblement la communication internationale.

Naissance d’UTF-8

Afin d’apporter une solution à ce problème, Joseph D. Becker a développé pour Xerox entre 1988 et 1991 le jeu universel de caractères Unicode. À partir de 1992, le consortium informatique X/Open a également cherché à établir un système qui prendrait la relève de l’ASCII et élargirait le répertoire de caractères. Ce nouveau codage devait malgré tout rester compatible avec l’ASCII. Une exigence à laquelle le premier codage intitulé UCS-2, qui se contentait de convertir les numéros de caractères en valeurs de 16 bits, n’a pas su répondre. UTF-1 a également échoué dans cette tâche puisque les attributions Unicode coïncidaient partiellement avec les chaînes de caractères attribuées par l’ASCII. Par conséquent, un serveur paramétré en ASCII affichait en partie des caractères erronés. Ce problème s’est révélé considérable, car la majorité des ordinateurs anglophones utilisait ce codage à cette époque. L’étape suivante fut franchie par le File System Safe UCS Transformation Format (FSS-UTF) de Dave Prosser qui est parvenu à vaincre le chevauchement avec les caractères ASCII.

En août de la même année, le projet a fait le tour des spécialistes. Les cofondateurs d’Unix Ken Thompson et Rob Pike travaillaient à l’époque sur le système d’exploitation Plan 9 pour les laboratoires Bell Labs, qui ont reçu de nombreux prix Nobel. Ils ont repris l’idée de Dave Prosser, développé un codage auto-synchronisant (chaque caractère indique ainsi combien de bits lui sont nécessaires) et défini des règles pour l’attribution des lettres qui pouvaient être représentées de façon différente dans le code (par exemple : « ä » en tant que caractère propre ou sous la forme de « a+¨ »). Ils ont appliqué ce codage avec succès à leur système d’exploitation et l’ont présenté aux responsables. Les grandes lignes du FSS-UTF, aujourd’hui connu sous le nom d’« UTF-8 », étaient alors posées.

Définition

L’UTF-8 est un codage de caractère de 8 bits pour Unicode. L’abréviation « UTF-8 » signifie « 8-Bit Universal Character Set Transformation Format », en français : « format de transformation du jeu universel de caractères 8 bits ». Un à quatre octets, composés chacun de huit bits, donnent un nombre binaire lisible par un ordinateur. Le codage attribue ce nombre à un caractère ou à un autre élément de texte. Cette structure auto-synchronisante et la possibilité de générer 221 nombres binaires permettent d’attribuer une chaîne de caractère distincte à chaque élément linguistique ou textuel dans toutes les langues du monde.

UTF-8 dans le jeu de caractères Unicode : un standard pour toutes les langues

Le codage UTF-8 est un format de transformation au sein du standard Unicode. La norme internationale ISO 10646 définit les grandes lignes d’Unicode, appelé dans cette norme « Universal Coded Character Set ». Les développeurs d’Unicode ont limité certains paramètres pour l’application pratique. Ce standard doit permettre un codage homogène et compatible à l’international des caractères et des éléments textuels. Lors de son introduction en 1991, Unicode définissait 24 systèmes d’écriture modernes ainsi que des symboles monétaires pour le traitement des données. En juin 2017, il en compte 139.

Il existe différents formats de transformation Unicode, abrégés en « UTF », qui permettent de reproduire les 1 114 112 points de code possibles. Trois formats ont réussi à s’établir : UTF-8, UTF-16 et UTF-32. Même s’ils présentaient certains avantages, les autres codages, tels que UTF-7 ou le SCSU, ne sont pas parvenus à s’imposer.

Unicode est divisé en 17 plans de 65 536 caractères. Chaque plan est composé de 16 colonnes et lignes. Le premier plan, le « Basic Multilingual Plane » (plan 0), regroupe une grande partie des systèmes d’écriture actuellement utilisés dans le monde ainsi que les caractères de ponctuation, des caractères de contrôle et des symboles. Cinq autres plans sont actuellement utilisés :

  • « Supplementary Multilingual Plane » (plan 1) : systèmes d’écriture historiques, caractères rarement utilisés
  • « Supplementary Ideographic Plane » (plan 2) : caractères chinois, japonais et coréens rares
  • « Supplementary Special-Purpose Plane » (plan 14) : caractères de contrôle individuels
  • « Supplementary Private Use Area – A » (plan 15) : utilisation privée
  • « Supplementary Private Use Area – B » (plan 16) : utilisation privée

Les codages UTF permettent d’accéder à tous les caractères Unicode. Leurs propriétés respectives conviennent à différents domaines d’application.

Les alternatives : UTF-32 et UTF-16

UTF-32 travaille toujours avec 32 bits, soit 4 octets. Sa structure simple permet d’augmenter la lisibilité du format. Dans les langues qui utilisent principalement l’alphabet latin et donc uniquement les 128 premiers caractères, ce codage demande beaucoup plus d’espace disque que nécessaire (4 octets au lieu d’1).

UTF-16 s’est imposé comme format d’affichage dans les systèmes d’exploitation comme Apple macOS et Microsoft Windows. Il est également utilisé dans de nombreux environnements de développement logiciel. Il s’agit de l’un des UTF les plus anciens encore utilisé à l’heure actuelle. Sa structure convient tout particulièrement à un codage peu encombrant des caractères linguistiques non latins. Seuls quelques rares caractères nécessitent une longueur de 4 octets, la plupart des caractères pouvant être affichés avec 2 octets (16 bits).

Efficace et évolutif : UTF-8

UTF-8 comporte jusqu’à quatre chaînes de 8 bits. Son prédécesseur, l’ASCII, comprend quant à lui une chaîne de 7 bits. Les deux codages définissent les 128 premiers caractères en les codant de la même façon. Ces caractères, qui viennent principalement de l’espace anglophone, sont ainsi représentés avec un octet à chaque fois. Pour les langues utilisant l’alphabet latin, ce format est le plus économe en terme d’espace disque. Les systèmes d’exploitation Unix et Linux l’utilisent en interne. C’est toutefois dans le cadre des applications Internet qu’UTF-8 joue son rôle le plus important, à savoir pour l’affichage du texte sur le World Wide Web ou dans les e-mails.

Sa structure auto-synchronisante permet de maintenir la lisibilité malgré une longueur par caractère variable. Sans limitation Unicode, UTF-8 permettrait (= 4 398 046 511 104) attributions de caractères. Avec la limitation à 4 octets d’Unicode, ce chiffre se porte dans les faits à 221, ce qui est plus que suffisant. Certains plans de l’espace de codage Unicode restent vides et peuvent accueillir de nombreux autres systèmes d’écriture. La précision des attributions empêche les chevauchements de points de code qui limitaient la communication par le passé. Même si l’attribution permise par UTF-16 et UTF-32 est tout aussi précise, UTF-8 utilise l’espace disque de façon particulièrement efficace pour le système d’écriture latin et est conçu pour permettre la couverture et la coexistence de différents systèmes d’écriture sans difficulté. Un affichage simultané et pertinent dans un champ de texte est ainsi possible sans problème de compatibilité.

Principes de base : codage UTF-8 et structure

Le codage UTF-8 séduit d’une part par sa rétrocompatibilité avec ASCII et d’autre part par sa structure auto-synchronisante, qui permet aux développeurs d’identifier plus facilement les sources d’erreurs a posteriori. UTF utilise 1 seul octet pour l’ensemble des caractères ASCII. Le nombre total de chaînes de bits est identifiable aux premiers chiffres du nombre binaire. Puisque le code ASCII comporte uniquement 7 bits, le tout premier chiffre est l’indicateur 0. Le 0 remplit l’espace disque entièrement jusqu’à 1 octet et indique le début d’une chaîne sans octet de continuation. En nombre binaire, le nom « UTF-8 » s’exprimerait par exemple comme suit avec le codage UTF-8 :

Caractère U T F - 8
UTF-8, binaire 01010101 01010100 01000110 00101101 00111000
Point Unicode, hexadécimal U+0055 U+0054 U+0046 U+002D U+0038

Le codage UTF-8 attribue aux caractères ASCII, comme ceux utilisés dans le tableau, une chaîne de bits unique. Tous les caractères et symboles suivants d’Unicode comportent de deux à quatre chaînes de 8 bits. La première chaîne est appelée octet de début de séquence et les chaînes supplémentaires des octets de continuation. Les octets de début de séquence commencent toujours par 11 alors que les octets de continuation commencent toujours par 10. Si vous recherchez manuellement un point précis dans le code, vous pouvez par conséquent identifier le début d’un caractère codé par les marqueurs 0 et 11. Le premier caractère de plusieurs octets imprimable est le point d’exclamation inversé :

Caractère ¡
UTF-8, binaire 11000010 10100001
Point Unicode, hexadécimal U+00A1

Le codage du préfixe permet d’éviter qu’un autre caractère soit codé au sein d’une chaîne d’octet. Si un flux d’octet commence au milieu d’un document, l’ordinateur affiche malgré tout les caractères lisibles correctement, puisqu’il n’affiche pas les caractères incomplets. Si vous recherchez le début d’un caractère, la limite de 4 octets impose de retourner au maximum trois chaînes d’octet en arrière pour retrouver l’octet de début de séquence, quel que soit le point où vous vous trouviez.

Autre élément structurant : le nombre de 1 au début de l’octet de début de séquence indique la longueur de la chaîne d’octet. Comme nous l’avons vu plus haut, 110xxxxx indique 2 octets, 1110xxxx indique 3 octets, 11110xxx 4 octets. Dans Unicode, la valeur d’octet attribuée correspond au numéro de caractère, ce qui permet un ordre lexical. Néanmoins, il existe des plages vides. La plage Unicode de U+007F à U+009F comporte des chiffres de contrôle non attribués. Le standard UTF-8 ne leur attribue aucun caractère imprimable, uniquement des commandes.

Comme indiqué précédemment, jusqu’à huit chaînes d’octet peuvent théoriquement se succéder avec le codage UTF-8. L’Unicode impose toutefois une longueur de 4 octets au maximum. Cela implique que les chaînes d’octet avec 5 octets ou plus ne sont pas valides par défaut. Par ailleurs, cette limitation reflète la volonté de présenter le code de façon aussi compacte – c’est-à-dire avec un minimum d’encombrement de l’espace disque – et aussi structurée que possible. Utiliser toujours le codage le plus court possible constitue une règle de base dans le cadre de l’utilisation d’UTF-8. La lettre ä est par exemple codée avec 2 octets : 11000011 10100100. En théorie, il est possible de combiner les points de code de la lettre a(01100001) et du tréma ¨ (11001100 10001000) pour afficher un ä : 01100001 11001100 10001000. Toutefois, dans le cadre d’UTF-8, cette forme est considérée comme trop longue et n’est donc pas autorisée.

Note

Cette règle explique pourquoi les séquences d’octet commençant par 192 et 193 ne sont pas autorisées. En effet, elles pourraient représenter avec 2 octets des caractères de la plage ASCII (0–127) qui ont déjà été codés avec 1 octet.

Certaines plages de valeurs Unicode n’ont pas été définies pour UTF-8, car elles existent déjà pour les demi-codets UTF-16. Cette vue montre quels octets sont autorisés dans UTF-8 sous Unicode d’après l’Internet Engineering Task Force (IETF) - les cellules colorées en vert sont les octets valides, les cellules colorées en rouge sont les octets invalides.

Conversion d’hexadécimal Unicode en binaire UTF-8

Les ordinateurs ne lisent que les chiffres binaires, tandis que l’être humain utilise un système décimal. Le système hexadécimal constitue une interface entre ces deux formes et permet de représenter les longues chaînes de bits sous une forme compacte. Pour ce faire, il utilise les chiffres de 0 à 9 ainsi que les lettres de A à F et se base sur le nombre 16. En tant que quatrième puissance de 2, le système hexadécimal convient mieux que le système décimal pour représenter des plages d’octet à huit chiffres. Un nombre hexadécimal correspond à un « nible » (ensemble de quatre bits) au sein d’un octet. Un octet avec huit nombres binaires peut donc être représenté avec deux nombres hexadécimaux seulement. L’Unicode utilise le système hexadécimal pour décrire la position d’un caractère au sein du système choisi. À partir de là, il est possible de déterminer le nombre binaire et finalement le point de code UTF-8.

Le nombre binaire doit tout d’abord être obtenu à partir du nombre hexadécimal. Vous pouvez ensuite intégrer les points de code dans la structure du codage UTF-8. Afin de simplifier la structuration, utilisez l’aperçu suivant qui indique combien de points de code rentrent dans une chaîne d’octet et quelle structure vous êtes susceptible de rencontrer dans telle ou telle plage de valeurs Unicode.

Taille en octets Bits libres pour la détermination Premier point de code Unicode Dernier point de code Unicode Octet de début de séquence / octet 1 Octet de continuation 2 Octet de continuation 3 Octet de continuation 4
1 7 U+0000 U+007F 0xxxxxxx      
2 11 U+0080 U+07FF 110xxxxx 10xxxxxx    
3 16 U+0800 U+FFFF 1110xxxx 10xxxxxx 10xxxxxx  
4 21 U+10000 U+10FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

Puisque l’ordre lexical pour la numérotation des points de code Unicode et des nombres binaires UTF-8 est respecté, vous pouvez présupposer le nombre d’octets en fonction de la plage de code. Dans la plage U+0800 et U+FFFF par exemple, UTF-8 utilise 3 octets. Il y a donc 16 bits disponibles pour exprimer le point de code d’un symbole. L’ordonnancement d’un nombre binaire déterminé selon le schéma UTF-8 s’effectue de droite à gauche, les éventuels espaces à gauche étant complétés avec des zéros.

Exemple :

Le caractèreᅢ(Hangul Junseong, Ä) est situé à la position U+1162 dans Unicode. Pour déterminer le nombre binaire, convertissez tout d’abord le nombre hexadécimal en nombre décimal. Chaque chiffre de ce nombre correspond à la puissance corrélée de 16. Le chiffre à droite a la valeur la plus faible avec 160 = 1. En partant de la droite, multipliez la valeur numérique du chiffre avec celle de la puissance. Additionnez ensuite les résultats.

2 * 1 = 2
6 * 16 = 96
1 * 256 = 256
1 * 4096 = 4096
4450 4450 4450 4450 4450

4450 est le nombre décimal déterminé. Convertissons maintenant ce nombre décimal en nombre binaire. Pour ce faire, divisez le nombre par 2 et reportez le reste, jusqu’à ce que le résultat soit 0. Le reste, lu de droite à gauche, correspond au nombre binaire.

4450 : 2 = 2225 Reste :  
2225 : 2 = 1112 Reste : 1
1112 : 2 = 556 Reste :  
556 : 2 = 278 Reste :  
278 : 2 = 139 Reste :  
139 : 2 = 69 Reste : 1
69 : 2 = 34 Reste : 1
34 : 2 = 17 Reste :  
17 : 2 = 8 Reste : 1
8 : 2 = 4 Reste :  
4 : 2 = 2 Reste :  
2 : 2 = 1 Reste :  
1 : 2 =   Reste : 1
Résultat : 1000101100010 Résultat : 1000101100010 Résultat : 1000101100010 Résultat : 1000101100010 Résultat : 1000101100010 Résultat : 1000101100010
hexadécimal binaire
   
1 0001
2 0010
3 0011
4 0100
5 0101
6 0110
7 0111
8 1000
9 1001
A 1010
B 1011
C 1100
D 1101
E 1110
F 1111

Vous pourrez suivre précisément les étapes de calcul dans cet exemple détaillé. Par ailleurs, si vous souhaitez convertir des nombres hexadécimaux en nombres binaires de façon simple et rapide, remplacez simplement chaque chiffre hexadécimal par les quatre chiffres binaires correspondants.

Pour le point de code Unicode U+1162, combinez les chiffres comme suit :

x1 = b0001

x1 = b0001

x6 = b0110

x2 = b0010

x1162 = b0001000101100010

Le code UTF-8 prévoit 3 octets pour le point de code U+1162, car ce point de code est situé entre U+0800 et U+FFFF. L’octet de début de séquence commence donc par 1110. Les deux octets de continuation commencent par 10. Complétez le nombre binaire avec les bits libres qui ne déterminent pas la structure, de droite à gauche. Complétez les bits restants de l’octet de début de séquence avec des 0 jusqu’à ce que l’octet soit complet. Le codage UTF-8 se présente alors comme suit :

11100001 10000101 10100010(le point de code inséré est mis en gras)

Caractère Point de code Unicode, hexadécimal Nombre décimal Nombre binaire UTF-8
U+1162 4450 1000101100010 11100001 10000101 10100010

UTF-8 dans les éditeurs

Même si UTF-8 est sans conteste le standard le plus répandu sur Internet, les éditeurs de texte simples n’enregistrent pas nécessairement les textes dans ce format par défaut. Microsoft Notepad utilise par exemple par défaut un codage qu’il désigne par « ANSI » (qui correspond en fait au codage « Windows-1252 » basé sur ASCII). Si vous souhaitez convertir un fichier texte depuis Microsoft Word au format UTF-8 (par exemple pour représenter différents systèmes d’écriture), procédez comme suit : cliquez sur « Enregistrer sous » et sélectionnez l’option « Texte brut » dans Type.

La fenêtre pop-up « Conversion de fichier » s’ouvre. Sous Codage du texte, sélectionnez le point « Autre codage » puis dans la liste l’option « Unicode (UTF-8) ». Dans le menu déroulant, « Terminer les lignes par », sélectionnez « Retour chariot/saut de ligne » ou « CR/LF ». Il n’y a rien de plus à faire pour convertir un fichier dans le jeu de caractères Unicode avec UTF-8.

Si vous ouvrez un fichier texte non marqué pour lequel vous ne connaissez pas le codage utilisé, le traitement de ce fichier pourra poser problème. Sous Unicode, on utilise dans de tels cas l’« indicateur d’ordre des octets » (« byte order mark » ; BOM). Ce caractère invisible permet d’afficher si le document est dans un format Big-Endian ou Little-Endian. En effet, si un programme décode un fichier codé en UTF-16 Little-Endian à l’aide de UTF-16 Big-Endian, le texte comportera des erreurs. Les documents reposant sur le jeu de caractères UTF-8 ne rencontrent pas ce problème, car l’ordre des octets est toujours lu comme une séquence d’octets Big-Endian. Dans ce cas, le BOM sert uniquement à indiquer que le document en question est codé en UTF-8.

Note

Dans certains codages (UTF-16 et UTF-32), les caractères représentés avec plus d’un octet peuvent avoir l’octet de bit de poids fort en première position (à gauche) ou en dernière position (à droite). Si l’octet de bit de poids fort (« Most Significant Byte », MSB) est situé en premier, le codage reçoit le complément « Big-Endian », s’il est situé à la fin, il reçoit le complément « Little-Endian ».

Le BOM est placé avant un flux de données ou au début d’un fichier. Ce marquage est prioritaire sur toutes les autres indications, même sur l’en-tête HTTP. Le BOM fait office de signature pour les codages Unicode et a le point de code U+FEFF. Selon le codage utilisé, le BOM peut adopter une forme codée différente.

Format de codage BOM, point de code : U+FEFF (hex.)
UTF-8 EF BB BF
UTF-16 Big-Endian FE FF
UTF-16 Little-Endian FF FE
UTF-32 Big-Endian 00 00 FE FF
UTF-32 Little-Endian FF FE 00 00

L’indicateur d’ordre des octets n’est pas utilisé lorsque le protocole l’interdit explicitement ou lorsqu’un type spécifique a déjà été attribué à vos données. Selon le protocole, certains programmes attendent des caractères ASCII. Comme UTF-8 est rétrocompatible avec le codage ASCII et l’ordre de ses octets est fixe, un indicateur d’ordre des octets est inutile. En réalité, Unicode ne recommande pas l’utilisation d’un tel indicateur sous UTF-8. Mais comme l’indicateur d’ordre des octets est présent dans l’ancien code et peut causer des problèmes, il est essentiel de savoir identifier un éventuel indicateur de ce type.

En résumé : le codage UTF-8 améliore la communication internationale

UTF-8 a l’avantage d’être rétrocompatible avec ASCII mais pas uniquement. Grâce à la longueur variable de la séquence d’octets et à l’immense quantité de points de code possibles, il permet d’afficher un nombre extrêmement important de systèmes d’écriture différents et d’utiliser l’espace disque nécessaire de façon efficace.

L’introduction de standards uniformes comme Unicode facilite la communication internationale. Grâce à l’utilisation de séquences d’octets auto-synchronisantes, le codage UTF-8 est caractérisé par un faible taux d’erreur dans l’affichage des caractères. Même si une erreur de codage ou de transmission se produit, vous pouvez facilement trouver le début de chaque caractère en déterminant l’octet qui commence par 0 ou 11 dans la séquence. Avec un taux d’utilisation de plus de 90 pour cent, UTF-8 est aujourd’hui le standard de codage incontesté pour les sites Internet.