charset vs encoding

Je me suis souvent demandé quelle est la différence entre charset et encoding. Pourquoi l’un est utilisé par HTML ?

<meta charset="utf-8">  

Et l’autre utilisé par XML ?

<?xml version="1.0" encoding="utf-8"?>  

La définition d’UTF-8 confirme que nous avons bien affaire à un « codage de caractères informatiques », qui dans ce contexte est la traduction d’encoding.

Pourquoi « charset » alors ? C’est ce que nous allons découvrir.

Retour aux sources

Ce terme apparaît dans la RFC 1341 où il est ajouté à MIME en tant que paramètre de l’en-tête Content-type :

A "charset" parameter may be used to indicate the character set of the body text.

« charset » étant l’abréviation de « character set », voilà qui ne nous aide pas beaucoup.

Toutefois si nous poursuivons notre lecture nous tombons sur une précision assez intéressante :

"US-ASCII" […] specifies that the body uses character coding that uses the exact correspondence of codes to characters specified in ASCII.

Traduit, cela peut donner :

"US-ASCII" […] indique que l’encodage du contenu utilise l’exacte correspondance des codes aux caractères définie par ASCII.

Voilà donc ce qu’est un charset : une correspondance des codes aux caractères.

Plus précisément, c’est une surjection dont l’ensemble de départ est constitué d’entiers et l’ensemble d’arrivée de caractères.

Vous avez peut-être déjà entendu parler de ces « codes entiers » sous le terme code point (point de code).

Illustrons maintenant ce charabia à l’aide de la table ASCII.

Table ASCII
Par ASCII-Table.svg: ZZT32derivative work: LanoxxthShaddow (ASCII-Table.svg) [Public domain], via Wikimedia Commons
  • Les entiers sous la colonne Decimal sont la représentation décimale des points de code.
  • Un point de code identifie un seul et unique caractère.
  • Un caractère est identifié par au moins un point de code.
  • Le charset est la fonction qui permet de passer du point de code à la colonne Char. Ici si nous lui passons 65, elle renverra « A ».

Le problème

Nous avons vu précédemment que la valeur du paramètre charset identifiait la fonction de transformation des entiers en caractères d’un encodage.

Pourquoi ne pas identifier directement l’encodage me demanderez vous ? Eh bien je n’en sais rien.

Toujours est-il qu’en 1992 cela ne pose pas de problème car l’ASCII et la famille des ISO-8859 consistent en un simple charset. Identifier ce charset, c’est donc identifier l’encodage.

Le souci, c’est que la spécification définit comme valeurs possibles de charset une liste administrée par l’IANA, qui est plutôt fournie (257 valeurs à l’heure où j’écris ces lignes). Parmi ces valeurs, arrêtons-nous sur ISO-2022-JP-2, définie dans la RFC 1554.

The text with "ISO-2022-JP-2" starts in ASCII [ASCII], and switches to other character sets of ISO 2022 [ISO2022] through limited combinations of escape sequences.

La particularité de cet encodage vient du fait qu’il peut utiliser des charsets différents et passer de l’un à l’autre via des séquences d’échappement (ce qui lui permet de représenter les caractères de plusieurs alphabets).

Ceci implique que pour transformer un point de code en caractère, il faut d’abord savoir quel charset est utilisé. On en conclut qu’un charset ne suffit pas à identifier un encodage.

Retour vers le présent

Lorqu’on prend conscience de l’erreur, la spécification a déjà été publiée, et ce point ne sera pas modifié. Ainsi, lorsque vient le tour de HTTP/1.0 on se base sur l’existant et lui ajoute l’en-tête Content-type et son paramètre charset.

Ensuite, HTML 2.0 définit l’attribut http-equiv de la balise <meta> qui permet de définir l’équivalent d’en-têtes HTTP à l’intérieur d’un document HTML.

<meta http-equiv="Content-Type" content="text/html;charset=utf-8">  

Enfin, HTML5 fait en 2008 du paramètre charset un attribut à part entière.

<meta charset="utf-8">  

Si vous écrivez « charset », c’est donc à cause d’une décision vieille de plus de 20 ans !

La spécification de XML a quant à elle débuté en 1996, assez tard pour définir l’attribut encoding.

La solution

Si j’ai écrit plus haut que malgré la découverte de l’erreur le paramètre a toujours gardé le nom de charset, c’est que la solution choisie a été de changer la signification de ce terme, ce qui est légitime mais entretient toujours une certaine confusion.

Puisque ce paramètre est censé identifier un encodage, il correspond désormais à l’ensemble des transformations d’un caractère vers une séquence d’octets sérialisée. On peut également y faire référence sous le terme « charmap », abréviation de « character map ».

Pour bien comprendre la différence, prenons l’exemple du caractère « é » en UTF-8.

Vous pouvez voir que le point de code du caractère est la valeur hexadécimale 00E9 dans le jeu de caractères codés d’Unicode.
Plus bas, 0xC3 0xA9 correspond à la séquence d’octets du caractère codé en UTF-8.

En 1992, le charset était la fonction qui transformait 00E9 en « é ».

Aujourd’hui, le charset est la fonction qui transforme « é » en 0xC3 0xA9.

Pour conclure

Comme vous avez pu le constater, la terminologie de l’encodage est un sujet épineux. Je vous invite donc à lire le rapport du Consortium Unicode sur le sujet, vous y apprendrez entre autres que si charset ne désigne pas un jeu de caractères, on traduit ce dernier par « abstract character repertoire ».

De quoi épater vos collègues…!