Unicode et UTF

On ne le croirait pas à priori mais le traitement des caractères par l’ordinateur est devenu un sujet complexe. Pour comprendre, commençons par un peu d’histoire.

Les ordinateurs ne comprennent que les nombres. Pour leur permettre de traiter les caractères, il a fallu associer un nombre à chaque caractère. Il y a eu quelques tentatives (codes de 5 bits, de 7 bits, de 8 bits, de 9 bits, etc). 2 codes ont survécu à cette première époque; ce sont l’ASCII (code de 7 bits) et l’EBCDIC (code de 8 bits, principalement utilisé par IBM). Le texte qui suit ne traitera pas de l’EBCDIC.

N’ayant que 7 bits, l’ASCII ne permet que 128 combinaisons. Il inclut 32 codes de contrôle, 52 caractères alphabétiques (majuscules et minuscules), 10 chiffres et des caractères de ponctuation. Étant d’origine états-unienne, ce code ne laissait aucune place aux caractères particuliers des autres langages. C’était frustrant.

Puis vint le PC (circa 1981). IBM  introduit les codepage. Ce sont des codes de 8 bits où les 128 premiers sont ceux de l’ASCII et les 128 autres sont disponibles pour les autres alphabets. Des compromis étaient nécessaires puisque 256 combinaisons ne sont pas suffisantes pour tous les caractères internationaux. Plus d’une centaine de codepage ont été créés, très souvent incompatibles. Par exemple, le é avait la valeur 130 dans le CP437, 233 dans le CP1252 et 142 dans le Mac-Roman de Apple. Il fallait choisir le codepage en fonction de l’ensemble des caractères à utiliser.

C’était la pagaille.

Vers 1978, Xerox proposa de créer un jeu de caractères universel qui portera plus tard le nom d’Unicode. La 1ère version arriva vers 2004 et nous en sommes aujourd’hui à sa 10ième version. Unicode (aussi connu sous le nom de ISO-10646), contient maintenant 136,755 caractères et symboles. Le problème est qu’il faut au moins 3 octets pour représenter autant de combinaisons. C’était trop!

L’UTF fut développé pour compresser Unicode. Le principe fondamental d’UTF est que les caractères les plus communs se représentent avec un seul octet et que les autres caractères sont représentés par 2, 3 ou 4 octets.

Plusieurs versions d UTF ont été développées:

  • UTF-8 utilise 1 à 4 octets
  • UTF-16 utilise 2 ou 4 octets.  (note1)
  • UTF-32 utilise 4 octets

Est-ce qu’Unicode solutionne tous les problèmes. Pas vraiment!

  • Un fichier ou flux UTF peut débuter par une empreinte (BOM) qui identifie quelle version d’UTF est utilisée et l’ordre des octets (big-endian ou little-endian). Malheureusement, cette empreinte n’est pas obligatoire.
  • Microsoft utilise une empreinte qui leur est propre.
  • La majorité des fichiers existants utilisent un codepage qui n’est pas inscrit dans le fichier.

Détecter quel encodage est utilisé dans un fichier n’est pas évident et plusieurs algorithmes ont été développés pour ce faire.  Mais aucun n’est parfait.

Linux fournit quelques outils pour faire ce travail:

  • La commande file identifie les encodages Unicode mais ne peut rien pour les codepage.
file fichier8
fichier8: UTF-8 Unicode text
  • La commande iconv convertit d’un encodage vers un autre (UTF-8 par défaut). Elle retourne une erreur si le fichier contient des caractères qui sont invalides. Plusieurs centaines d’encodages et codepage sont reconnus. Cette approche permet de vérifier une hypothèse mais pas d’identifier l’encodage.
iconv -f utf8 fichier8 > /dev/null ;; echo OUIOUI
if iconv -f utf16 fichier8 >/dev/null 2>&1; then echo OUI; else echo NON; fi
NON
  • Tous les Linux récents utilisent UTF-8 par défaut. La commande grep permet de repérer les textes qui ont des fautes d’encodage UTF-8.
grep -avx  '.*'  fichier

listera toutes les lignes du fichier qui contiennent un encodage invalide en UTF-8.

Note1: S’il y a une empreinte en début de fichier, UTF-16 devient UTF-16BE (big-endian) ou UTF-16LE (little-endian)

Références