Le web de Dominique Guebey – Bazar informatique

Page : http://www.dg77.net/tekno/xhtml/codage.htm


   D o m i n i q u e   G u e b e y    J u n g l e      Bazar informatique

Le codage des caractères

Sommaire :

Préambule

Les documents Web, qui sont ici notre propos, et beaucoup d’échanges, protocoles et services associés, sont fondés sur une structure et des données texte, c’est à dire composés de suites de caractères identifiables (chiffres et lettres, signes de poncturation, espaces…). Sur l’opposition texte (lisible) et binaire (illisible) : voir plus bas. Le texte a l’avantage d’être facilement convertible et portable entre différents types d’ordinateurs, terminaux, systèmes ou appareils de transmission. Mais cette universalité ne saurait être sans l’adoption de conventions et de normes. Dès lors, une initiation à l’encodage est un passage obligé si on veut répondre aux exigences minimales de qualité et ne pas se trouver dépourvu dans des cas comparables à ce qui suit.

Le texte attendu :

Ich bin der Geist, der stets verneint !
Und das mit Recht ; denn alles, was entsteht,
Ist wert, dass es zugrunde geht ;
Drum besser wär's, dass nichts entstünde1.

Le texte obtenu :

Ich bin der Geist, der stets verneint !
Und das mit Recht ; denn alles, was entsteht,
Ist wert, dass es zugrunde geht ;
Drum besser wär?s, dass nichts entstünde.

L’apostrophe du dernier vers pose problème. Explication classique : le directeur de publication s’est laissé convaincre par son neveu qu’il lui fallait un site internet. Bombardé webmestre, ledit neveu n’a eu de cesse que de coller dans des pages HTML dûment étiquetées au format standard iso-8859-1 des textes copiés tout droit de son traitement de texte Microsoft codant en cp-1252. L’anomalie sur le caractère apostrophe est un signe très sûr de cette aberration.

Il y a encore plus spectaculaire. Le texte attendu :

So ist denn alles, was ihr Sünde,
Zerstörung, kurz das Böse nennt,
Mein eigentliches Element.

Le texte obtenu :

So ist denn alles, was ihr Sünde,
Zerstörung, kurz das Böse nennt,
Mein eigentliches Element.

Explication : on a lu en iso-8859-1 un texte encodé en fait en UTF-8. Cette dernière norme permet de représenter un très grand nombre de caractères, mais pour beaucoup d’entre eux, comme les voyelles accentuées, l’encodage prend deux fois plus de place, d’où l’apparition des deux caractères bizarres à la place d’un seul.

De la même façon, la chaîne de caractères « arrêt système » dans un fichier de commandes saisi en UTF-8 s’affichera comme suit :

** arrêt système en attente **

Dans ce cas, la console du type ancestral VT100 a lu les données comme du bon vieux CP850.

Reprenons donc les choses par le début ; les connaisseurs passeront ce qui leur est superflu.

Du BIT à l’OCTET

Une mémoire d’ordinateur réside :

  1. Soit dans une mémoire vive (circuit électronique miniaturisé) ; mémoire qui s’efface dès que le courant est coupé. Les données, une fois qu’elles y sont inscrites, sont très rapidement accessibles.
  2. Soit sur un support de stockage permanent. Ce peut être :
    • Un disque magnétique recouvert d’oxyde de fer (suivant la même technique que les classiques bandes magnétiques), tournant à grande vitesse. Le disque comporte généralement plusieurs plateaux, les têtes de lecture flottent à faible distance (quelques nanomètres) de la surface : ne pas secouer…
    • Un système optique (comme les CD-Rom ou DVD), également rotatif, réinscriptible ou pas. Un faisceau laser est chargé de la lecture et de l’inscription.
    • Une EPROM (Erasable Programmable Read Only Memory), circuit utilisé pour conserver des instructions et données utiles au démarrage et fonctionnement de tout appareil électronique. Il ne peut être effacé et réécrit que par un traîtement particulier.
    • Une mémoire flash, similaire à l’EPROM sauf qu’elle est réinscriptible à volonté. Grâce à la baisse prodigieuse des coûts, les mémoires flash sont devenues très répandues : qui ne possède une clé USB ou une carte SD ? On ne concevrait pas de Smartphone sans ce génial dispositif. En effet, ce type d’unité autorise de véritables « disques virtuels ». Ces derniers, sous la forme de SSD, sont devenues une alternative sérieuse aux disques mécaniques traditionnels.

L’information traitée sous forme d’unités élémentaires électriques ne peut prendre que 2 positions, (+ ou -, dites 1 ou 0), selon que l’emplacement est chargé positivement ou négativement. Cette unité d’information fondamentale est un « bit », constitutif d’une numération binaire (nous utilisons couramment un système décimal – 0 à 9). On conviendra que disposer de seulement deux valeurs est très limitatif, à côté par exemple des 26 lettres de notre alphabet latin2.

En informatique, l’unité usuelle n’est pas le bit mais plutôt le groupe de 8 bits qu’on nomme octet, ou byte (prononcer baïte). Par facilité, on peut l’appeler “caractère”, mais on va voir qu’un caractère n’est pas toujours strictement un octet.

Un octet peut prendre 256 valeurs différentes (soit le produit : 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 ; ou : 2 puissance 8) allant de 0 à 255. Exemples avec l’équivalent en notation décimale habituelle :

Notation hexadécimale

Une notation commode est l’hexadécimale. Au lieu d’utiliser la base dix avec les chiffres de 0 à 9, on utilise une base 16 (2 puissance 4) en ajoutant les 6 lettres de A à F. Ce qui s’inscrit en décimal : 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 devient 0 1 2 3 4 5 6 7 8 9 A B C D E F en hexadécimal.

En hexadécimal, un octet se note avec seulement 2 caractères (le maximum est FF au lieu de 255) :

Pour signaler l’utilisation de l’hexadécimal, une habitude ancienne est d’ajouter “x” avant ou après. Exemple : dans la norme courante (voir plus bas ASCII) le signe astérisque a reçu le code 42 (décimal) ou 0x2a (hexadécimal) ; ou encore '2a'x. Dans le programme REXX utilisé pour générer certaines pages du présent site, on trouvera des opérations sur le caractère de tabulation (code 09) : CALL REMPLACE '09'x, ' ' par exemple.

La même notation peut se trouver dans des entités en X/HTML : le u avec accent aigu, utile en espagnol, se code ֣ ce qui est la même chose que ֣ (sur la notion d’entité, voir plus loin [http://www.dg77.net/tekno/xhtml/specarac.htm#ent]).

Voici une table de conversion. Les lignes correspondent au premier caractère hexadécimal, les colonnes au second. Le contenu donne les valeurs décimales. Exemple : x41=(4x16)+1=65 (1=2e colonne, ne pas oublier qu’il s’agit non pas de nombres mais de numérotage qui commence par zéro).

Conversion HEX-décimal
x   0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
0  000 001 002 003 004 005 006 007 008 009 010 011 012 013 014 015
1  016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031
2  032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047
3  048 049 050 051 052 053 054 055 056 057 058 059 060 061 062 063
4  064 065 066 067 068 069 070 071 072 073 074 075 076 077 078 079
5  080 081 082 083 084 085 086 087 088 089 090 091 092 093 094 095
6  096 097 098 099 100 101 102 103 104 105 106 107 108 109 110 111
7  112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
8  128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
9  144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
A  160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
B  176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
C  192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
D  208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223
E  224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239
F  240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255

Il est utile de disposer d’un éditeur hexadécimal, par exemple XVI32 (sous MS Windows), Shed, Khex, Ghex (UNIX/Linux), Hexedit (MacOs). Cet outil très simple permet d’inspecter et éventuellement modifier n’importe quelle donnée grâce à l’affichage exact du code interne des octets.

Octet, sextet et Base64

Dans aucune norme les 256 codes possibles ne correspondent à autant de caractères affichables. En revanche l’hexadécimal permet de représenter n’importe quelle suite d’octets. Mais c’est avec l’inconvénient d’une lecture laborieuse : il faut deux caractères par octet, qu’il convient de séparer du précédent et du suivant. Cette question de représentation dépasse celle du simple confort de visualisation : le traîtement de données imprévues par un programme peut provoquer des effets dommageables, comme le « plantage » de sorties sur écran ou imprimante.

Base64 pallie cet inconvénient, en utilisant des groupes de six bits au lieu de huit. Dans cet encodage, chaque groupe de vingt-quatre bits (trois octets) est découpé en quatre groupes de six.

Binaire Déc. Hex. Représentation
000000 à 011001 0 à 25 x00 à x19 Alphabet latin en majuscules
011010 à 110011 26 à 51 x1A à x33 Alphabet latin en minuscules
110100 à 111101 52 à 61 x34 à x3D Chiffres, 0 à 9
111110 62 x3E "+"
111111 63 x3F "/"

Base64 est intéressant pour représenter des blocs de données sans signification directe, tels des images. Un exemple magistral : afficher une clef de signature et cryptage PGP / GPG [http://www.dg77.net/signature.htm].

Exemple de quinze octets tirés d’un fichier image JPEG dans lequel on a inévitablement des caractères non présentables. On obtient vingt caractères en Base64 :

Prenons un email comportant un document PDF en pièce jointe (eMail « Multi-part » comprenant un « attachment »). Avec les options Affichage > Code source du message du programme client mail Mozilla Thunderbird, voici une petite portion de ce qui peut apparaître (on ne montre ici que le début du PDF) :

------=_Part_796_140363998.1552991548805
Content-Type: application/pdf; name=tranxen021-2019-num25.pdf
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename=tranxen021-2019-num25.pdf
X-Attachment-Id: f19b9d36-d432-4f47-ace4-2ae95aac4bac
Content-ID: <f19b9d36-d432-4f47-ace4-2ae95aac4bac>

JVBERi0xLjQKJcOkw7zDtsOfCjIgMCBvYmoKPDwvTGVuZ3RoIDMgMCBSL0ZpbHRlci9GbGF0ZURl
Y29kZT4+CnN0cmVhbQp4nJ1bS4/kthG+z6/Q2cCM+RYJDBpQqyUjvtlZIIcgpyROYOwmWF/89/PV
gxSpnu414vHOShRZrHd9LGnNm51+f/k6GfzEEt/clIN9y9Nv/3z5y3fTf17MW074bzr//du/XmJ6
m6dk4luYvrxEX/T680TXsdg3T9c0abips/798st3urEhctdPLy4GsDMn/5amT/+Yvt/tVKZPv/z1
3Vjj8OMvMb6bcEn23USTzIxrO7+bfHHu3RTjLq/W8gS6S8abBb/d5W+ffnzZPr38dN7OONouuLdy
2i6bq1mFzs1s+NmtwR9rHQZfwcPNehtwH49J/MAmXQm27HwJ4Z2WYhQLmEDUeRnX5mLNe5tdLjG9

Noter les spécifications Content-Type et Content-Transfer-Encoding. On est en présence d’un fichier correspondant à un type Mime. Pour en savoir un peu plus, aller sur cette page [http://www.dg77.net/tekno/xhtml/mime.htm].

Et si le nombre de bits du fichier n’est pas un multiple de vingt-quatre ? Et si la norme en cours interdit le caractère “/” ? Pour plus d’informations, consulter la RFC 20453.

On passera sur Base32 (codage sur cinq bits) ; avec ASCII, on trouvera plus bas un encodage à sept bits.

Binaire contre Texte, et autopsie de fichiers

L’objet couramment manipulé dans les ordinateurs est le fichier (en anglais file), bloc de données plus ou moins structurées. Un fichier peut contenir différents types d’informations, en fonction de son utilisation. Cela va de la table contenant un fichier client, avec ses colonnes bien définies (nom, adresse, références bancaires, etc.) jusqu’aux suites cabalistiques d’instructions et d’adresses machine des programmes compilés ; sans parler des fichiers d’images, sons et autres envahissants objets multimédia.

Lorsqu’il est traîté par l’unité centrale de l’ordinateur, un fichier est lu et analysé bit après bit par le système d’exploitation. Le même traîtement s’appliquera aussi bien à des données stockées sur disque qu’introduites par un terminal (clavier, lecteur de codes-barre, sonde industrielle, etc.) ou une unité de télécommunication. Ce défilement des données explique qu’un fichier puisse être compris comme un flux, d’où le terme général de « flot de données », ou stream en anglais.

Il est question ici de données texte, par opposition avec le binaire. Il n’existe pas de définition formelle de ce qu’est un fichier binaire, et guère mieux pour le texte. En pratique, le contenu texte sera lisible par l’être humain, et le binaire ne le sera pas. On remarquera souvent qu’un fichier binaire n’est pas divisé en enregistrements ou lignes séparées par un caractère de saut ou fin-de-ligne, mais ceci n’est pas vraiment significatif. Des fichiers textes peuvent se retrouver sous forme binaire s’ils sont compressés4 ou cryptés.

Un fichier peut contenir en même temps du texte et du binaire. C’est le cas pour un tableau Excel. L’illustration (fig. 2) donne un autre exemple : une image JPEG, d’un artiste aux mérites probablement méconnus. Le format JPEG (qui est une méthode de compression particulière) peut embarquer des indications textuelles sur le sujet. L’image suivante (fig. 3) montre le même fichier visionné dans l’éditeur hexadécimal XVI32. [http://www.chmaas.handshake.de/] Le panneau de gauche donne les codes hexadécimaux. Dans celui de droite, on distingue les mentions IPTC, renseignées pour les besoins de la démonstration (copyright, légende, source, auteur…). La suite contient les données binaires non représentables (en principe 24 bits pour chaque pixel) qui permettront à un programme adapté de faire apparaître l’image à l’écran ou en impression.


Figure 3
l:427, h:399

Les langages de programmation sont classés en langages interprétés et langages compilés. Dans le premier cas, c’est au stade de l’exécution que l’ordinateur, à l’aide d’un logiciel interpréteur, se charge de traduire en données binaires (code machine) les instructions. Dans le second cas, ces instruction produites par le programmeur sont converties préalablement, par une opération appelée compilation. Mais quel que soit le type de langage, il faut commencer par écrire les instructions sous forme texte.

Un intérêt des programmes compilés, qui sont des fichiers binaires, est d’être plus compacts et plus rapides d’utilisation que les programmes à interpréter. Ceci est dû au fait qu’ils sont plus proches du fonctionnement intime (au niveau matériel) de la machine. Mais il y a des contreparties à cette puissance des données binaires, en dehors du fait qu’elles sont proprement incompréhensibles. Elles doivent être lues et manipulées par un programme ad-hoc, et suivre les particularités de la plate-forme informatique utilisée5. A l’inverse, les fichiers textes ne souffrent pas de cette dépendance au système.

Ci-dessous un membre de programme en langage interprété REXX.

  if zsep > 0 & zsep < 5 then DO
    poslf = POS(' ',ligne,posl)
    trav2 = SUBSTR(ligne,1,zsep-1)
    if poslf == 0 then trav2 = trav2 || ' ' || SUBSTR(ligne,posl+1,long-posl)
                  else trav2 = trav2 || ' ' || SUBSTR(ligne,posl+1,poslf-posl)
    trav2 = trav2 || ' ' || SUBSTR(ligne,zsep+1,posl-zsep-1) || ' '
    if poslf > 0 then trav2 = trav2 || SUBSTR(ligne,poslf+1,long-poslf)
    ligne = trav2
  END

On observe que (comme dans tous les autres langages de programmation), le jeu de caractères utilisé dans les instructions est composé d’un ensemble limité. Il s’agit des codes ASCII.

ASCII

American Standard Code for Information Interchange. L’encodage ASCII utilise 7 bits soit 128 possibilités, le 8e bit étant destiné au contrôle de parité6, ou à gérer les interruptions. Ceci était conforme aux machines anciennes fonctionnant sur 8 bits. Aujourd’hui seulement 128 codes d’interruption ferait crier au scandale tout ingénieur-système7.

Norme fondamentale publiée en 1967 (dernière version : 1986), ASCII suffit à l’alphabet anglais, dépourvu d’accents. Beaucoup d’autres encodages sont dérivés d’ASCII, lequel définit les codes pour 95 caractères “imprimables”, numérotés de 32 à 126 ; et 33 caractères dits non imprimables, la plupart obsolètes.

Type Binaire Déc. Hex. Caractères
Caractères "non imprimables" 00000000 à 00011111 0 à 31 x00 à x1F ex: touches Entrée, tabulation, fin de ligne, retour chariot, verrouillage/déverrouillage clavier…
01111111 127 x7F Touche de suppression [DEL]
Espace 00100000 32 x20
Caractères de ponctuation et signes divers 00100001 à 00101111 33 à 47 x21 à x2F ! " # $ % & ' ( ) * + , - . /
Chiffres 00110000 à 00111001 48 à 57 x30 à x39 0 1 2 3 4 5 6 7 8 9
Divers autres signes 00111010 à 01000000 58 à 64 x3A à x40 : ; < = > ? @
Lettres en majuscules 01000001 à 01011010 65 à 90 x41 à x5A A B C D … X Y Z
Divers autres signes 01011011 à 01100000 91 à 96 x5B à x60 [ \ ] ^ _ `
Lettres en minuscules 01100001 à 01111010 97 à 122 x60 à x7A a b c d … x y z
Divers autres signes 01111011 à 01111110 123 à 126 x7B à x7E { | } ~

Noter que pour passer de majuscules en minuscules, il suffit d’ajouter 32 (mettre à 1 le 3e bit, ou +100000) ; et vice-versa.

Voir la TABLE COMPLETE en annexe.

En ASCII les caractères accentués manquent, ce qui indiffère les anglophones mais pêche pour à peu près tout le reste du monde.

John Donne s’affichait dès l’origine sans difficulté :

O my America ! my new-found-land,
My kingdome, safeliest when with one man man’d
My Myne of precious stones, My Emperie,
How blest am I in this discovering thee !8

Mais il y avait problème pour un Luis de Góngora, avec ses ó, ¿, é, á, í et autres ñ  :

Si Amor entre las plumas de su nido
prendió mi libertad, ¿ qué hará ahora,
que en tus ojos, dulcísima señora,
armado vuela, ya que no vestido ?9

On s’est donc ingénié à concevoir des tables de codages qui prévoient le maximum de caractères accentués ou spéciaux. Ces tables de correspondances sont nommées Code Page, ou Page de Code en jargon franglais..

CP850 et quelques autres pages de codes

Origines

Ce sont les pages de code IBM PC, descendantes d’ASCII, mais codées sur 8 bits au lieu de 7, ce qui double les possibilités.

Quelques CP
CP437

CP437 est presque aussi ancien qu’ASCII et n’est cité ici que pour son rôle historique. Son affichage dans un éditeur graphique peut produire des effets curieux. CP437 ne permet pas une internationalisation satisfaisante.

CP850

CP850 est toujours susceptible d’être renconté. C’est l’encodage type de DOS « Latin-1 » d’Europe occidentale, encore utilisé dans les terminaux (“invite de commande”, “shell”…) sur les machines tournant sous MS-Windows en CP1252 (cf infra). Cette table a une partie commune avec CP437. Elle contient les mêmes caractères (quoique à des positions différentes) qu’ISO-8859-1. Voir encore :

CP-1252 / Windows-1252

La série des pages de code CP1250 à 1258 visait à une meilleure internationalisation des affichages d’ordinateurs. Plus particulièrement, Windows-1252 est un encodage similaire à CP850 et ISO-8859-1, à la différence près que cette table comporte des caractères imprimables à la place de caractères de contrôle (0x80 à 0x9F) interdits en HTML. Cette page de code a d’ailleurs varié dans le temps tout en conservant la même référence… Voir la TABLE en annexe.

Comme il s’agit de l’encodage par défaut du très répandu système d’exploitation Microsoft Windows, il ne faut pas s’étonner de voir la plupart des navigateurs Web en tenir compte automatiquement. Quand se présente un code interdit dans une page censée être ISO-8859-n, ils le traîtent sous la forme prévue par Microsoft.

Ce n’est pas une raison pour tomber soi-même dans ce coupable laxisme quand on crée des documents XML. Il faut garder en tête que le XML/XHTML n’est pas simplement fait pour être affiché. Ces documents doivent pouvoir être traîtés par des programmes (robots, parsers et tout autre logiciel) ; sinon c’en est fait de l’interopérabilité.

On veillera toujours à ce que l’éditeur qu’on utilise ait l’encodage convenablement configuré.

KOI8

KOI8-R : page de code mono-octet pour le Russe et l’Albanais. KOI8-U : idem pour l’Ukrainien. Ces encodages furent mis au point de l’autre côté du rideau de fer. Ils permettent une translitération aisée (quoique inversant majuscules et minuscules) de l’alphabet cyrillique aux lettres latines, puisqu’il suffit de passer le premier bit de un à zéro pour passer du premier type au second. Il peut être utile de connaître l’existence de ces encodages, car on les rencontre plus souvent qu’ISO 8859-5 ou Windows-1251. La table KOI8-R figure en annexe.

ISO 8859

La « page de code » 8859-1 assez connue, souvent appelée Latin-1, forme la première partie de la norme internationale ISO/CEI 8859 (ISO = Organisation Internationale de Normalisation), pour le codage des caractères en informatique. Elle définit 191 caractères codés sur un octet (Voir en annexe).

Plus de 10 tables différentes ont été ainsi définies.

Le système ISO-8859 est peu satisfaisant. Je m’en suis rapidement rendu compte dans certaines pages de mon site Web, à l’origine défini en 8859-1. J’y enregistrais des résultats sportifs, et chaque fois que je voulais incorporer des classements tchèques ou polonais (pour ne citer que les cas les plus fréquents), il fallait que je les retouche manuellement. Je n’ai plus de soucis depuis le passage à UTF-8.

Substitutions et échappements divers

Percent Escape

De nos jours, à peu près tout le monde a l’occasion de lire ou utiliser des URL ou URI (voire URN)10. Ce sont ces identificateurs (du genre http://www.monsite.fr) qui permettent d’atteindre en un tournemain (et par la grâce des routeurs et serveurs de noms de domaine) une « ressource » quelque part dans le vaste monde. Ces identifiants sont basés sur le code ASCII, et par suite ne peuvent contenir qu’un jeu limité de caractères. Pour en représenter d’autres, un mécanisme a été défini11. Voici un exemple simple mais assez courant : supposons qu’un site web contienne des liens vers des documents bureautiques ou autres. On sait bien que leurs dénominations sont fréquemment laissées à la totale fantaisie de leurs auteurs, qui n’hésiteront pas à y mettre en particulier des espaces. On pourra avoir ainsi un état nommé “statistiques pour 2016.pdf”. L’URL pour l’atteindre et l’afficher dans le navigateur pourra être quelque-chose comme : http://www.dom.com/archives/statistiques%20pour%202016.pdf.

La chaîne %20 spécifie le caractère ASCII "espace". Le signe pourcentage est dit « caractères d’échappement » (escape character). Outre l’espace, voici les autres codes réservés (à jour en janvier 2005) :

Quoted printable

Quoted printable est une technique destinée à contourner les limites du protocole d’envoi des courriers électroniques SMTP, qui ne connaît lui aussi que l’ASCII. Supposons qu’un correspondant nous confie ce qui suit :

Coordonnées expéditeur Sender
Nom-Name:
eMail:

Texte:

Le texte transmis à votre programme client de courrier électronique sera un peu différent :

L=E0, j'ai eu =E0 r=E9veiller un monde qui n'=E9tait =
connu que de moi, je n'ai rencontr=E9, en errant dans =
cette soci=E9t=E9 =E9vanouie, que des souvenirs et le =
silence ; de toutes les personnes que j'ai connues, =
combien en existe-t-il aujourd'hui ? Les habitants de =
Saint-Malo s'adress=E8rent =E0 moi le 25 ao=FBt 1828, =
par l'entremise de leur maire, au sujet d'un bassin =
=E0 flot qu'ils d=E9siraient =E9tablir. Je =
m'empressai de r=E9pondre, sollicitant en =E9change =
de bienveillance, une concession de quelques pieds =
de terre, pour mon tombeau, sur le Grand-B=E9.

Il s’agit d’un e-Mail comportant dans sa partie prologue (occultée par les interfaces utilisateurs mais visible avec la fonction « affichage source ») une indication charset="iso-8859-1". Procédé : on utilise le signe égal ("=") comme caractère d’échappement : pour chaque caractère qui n’entre pas dans la liste des codes ASCII, on positionne un "=" suivi par la valeur hexadécimale (dans l’encodage spécifié, ici iso-8859-1) du caractère à représenter. Le "=" doit lui aussi être remplacé par "=61" bien qu’il entre dans la gamme ASCII. Il y a quelques autres règles, parmi lesquelles la limitation à 76 caractères de chaque ligne, qui doit se terminer par un "=" isolé (non traduit au décodage).

Si on veut concevoir son propre programme de réception et traîtement des informations, automatiser le décodage (comme l’encodage) quoted-printable n’est pas un problème : cela fait belle lurette que les programmeurs de tous les horizons ont rivalisé dans tous les langages pour fournir leurs scripts et autres API.

Quoted-printable fait partie des encodages MIME (voir dans la page Types MIME un e-Mail bulgare [http://www.dg77.net/tekno/xhtml/mime.htm#ex] comme autre exemple).

EBCDIC, CCSID et DBCS

Extended Binary Coded Decimal Interchange Code

Qui dit EBCDIC dit IBM. Comme les machines de Big Blue sont assez répandues, il n’est pas rare, en entreprise, de devoir aller piocher dans la base de données d’un de ces engins. Par conséquent, on se doit de connaître quelques termes et concepts de base, ne serait-ce que pour ne pas subir un trop vif choc culturel le jour où on rencontre l’équipe qui s’occupe de tout ça.

Carte perforee IBM l:727, h:337

EBCDIC est un codage sur 8 bits, création d’IBM, utilisé depuis le S/360 sorti le 7 avril 1964. Sa conception d’origine est reliée aux cartes perforées utilisées à l’époque pour entrer les données dans les ordinateurs. EBCDIC a été maintenu depuis, et il est toujours mis en oeuvre sur les mainframes (aujourd’hui zSeries sous z/OS) et "mini" (AS/400, alias iSeries, alias System i5…). En revanche, les PC de type IBM n’utilisent pas EBCDIC mais les mêmes encodages issus d’ASCII que leurs concurrents. EBCDIC est ou était reconnu par d’autres machines, comme les Fujitsu-Siemens et certains Unisys.

En EBCDIC, un byte est divisé en deux parties (« nibbles »). La première, dite zone, indique la catégorie du caractère, la seconde, nommé digit, identifie le caractère lui-même. Dans l’exemple de table donnée en annexe, « & » porte le code 0x50 (hexadécimal) ou 80 (décimal) au lieu de 0x26/38 pour l’ASCII. La lettre L sera représentée par 0xD3…

Capture ecran iSeries, dsppfm vue hexadecimale l:648, h:512

Noter quelques caractéristiques d’EBCDIC :

SBCS et DBCS

DBCS Double Byte Character Set : par opposition au SBCS (Simple…) ce codage sur deux octets connaît plusieurs variantes destinées à couvrir les besoins des écritures japonaises, coréennes et chinoises.

CCSID

IBM a prévu quelques dizaines de pages de code, chacune portant un numéro appelé le CCSID (Coded Character Set IDentifier). Voir en annexe les listes détaillées.

Quelques valeurs remarquables :

Un peu de pratique

WDSC - Websphere Developpment Studio Client permet de saisir une ligne de programme source en Hexadécimal, avec le choix simultané de plusieurs encodages. Pour cela : Clic droit sur la vue > Source > Edition hexa. ligne. Sur l’illustration, on voit que R se code U+0052 en Unicode, 0x52 en CP1252 et 0xD9 en EBCDIC.

WDSC l:603, h:436

Pour ceux qui ont à mettre les mains dans le cambouis, spécialement sur iSeries (ex AS/400), voir la page dédiée à l’art du CCSID sur iSeries.

ISO 10646 et UNICODE

Cadre général

A côté d’ISO/IEC existe le consortium UNICODE issu de l’association de constructeurs d’ordinateurs, dont la visée première était de lutter contre le chaos des jeux de caractères et de favoriser l’internationalisation des systèmes. Unicode collabore étroitement depuis les années 1990 avec ISO/IEC et ses normes sont strictement compatibles avec les définitions d’ISO/IEC 10646.

Face aux limites du codage sur 8 bits, on eut tôt fait de proposer des encodages sur plus d’un octet. D’où ISO/IEC 10646 Universal Multiple-Octet Coded Character Set (Jeu de caractères multi-octets universel), abrégé en UCS. Le but est d’encoder tous les caractères de tous les langages du monde, plus les symboles, mathématiques et autres. Deux modes ont été défini : UCS-2 (sur 16 bits) et UCS-4 (sur 31 bits).

Présentation — BMP et Plans

De même que la notation hexadécimale se signale par un "x", un caractère Unicode se décrit avec "U+" suivi de la valeur hexadécimale correspondant au point de code (code point) défini par Unicode. Cette valeur comporte deux octets entre U+0000 et U+FFFF, plage qu’on appelle le plan de base multilingue ou BMP. Il s’agit des trois premières lignes du tableau ci-dessous. La suite (quatrième ligne) comporte 5 chiffres (hexa.) pour les 15 plans suivants (entre U+10000 et U+10FFF), ou 6 chiffres pour le dernier plan (U+100000 et la suite). UNICODE impose en fait une limite égale à +10FFFF.

Numéro UNICODE Nombre d’octets
Décimal Hexadécimal UTF-8 UTF-16 UTF-32
0 - 127 U+0000 - U+007F 1 2 4
128 - 2.047 U+0080 - U+07FF 2
2.048 - 65.535 U+0800 - U+FFFF 3
65.536 - 1.114.111 U+10000 - U+10FFFF 4 4
UCS-2

Dans la formule UCS à deux octets, on définit 256 rangées comprenant chacune 256 cellules. Soit 65.536 positions. La première rangée, ou rangée 0, contient tout simplement le jeu ISO/IEC-8859-112

UCS-4

La formule UCS à 4 octets utilise 31 octets seulement, le premier étant obligatoirement 0. Cet espace de codage de 2.147.483.648 positions, comporte 128 groupes de 256 plans. Le premier octet définit le groupe, le second indique le plan. Les troisièmes et quatrièmes donnent les rangées et numéro de cellule de chaque caractère. Le plan 0 du groupe 0 correspond à UCS-2(BMP).

Niveaux d’implémentation

Un système peut ne pas supporter toute l’étendue d’UCS. Trois niveaux ont été définis

UTF-8

UTF-8 (UCS transformation format 8 bits) est un format de longueur variable, défini pour les caractères Unicode. Chaque caractère est codé sur une suite de un à quatre octets. UTF-8 a été conçu pour assurer une bonne compatibilité avec les logiciels prévus pour traiter des caractères d’un seul octet. Les protocoles de communication d’Internet échangeant du texte doivent supporter UTF-8.

Description

Unicode attribue un numéro à chaque caractère. Les caractères de numéro 0 à 127 sont codés sur un octet dont le bit de poids fort est toujours nul. Les caractères de numéro supérieur à 127 sont codés sur plusieurs octets. Dans ce cas, les bits de poids fort du premier octet forment une suite de 1 de longueur égale au nombre d’octets utilisés pour coder le caractère, les octets suivants ayant 10 comme bits de poids fort.

Ce principe pourrait être étendu jusqu’à six octets pour un caractère, mais UTF-8 pose la limite à quatre. Ce principe permet également d’utiliser plus d’octets que nécessaire pour coder un caractère, mais UTF-8 l’interdit.

Dans toute chaîne de caractères UTF-8, on remarque que :

Définition du nombre d’octet utilisé
Représentation binaire Signification
0xxxxxxx 1 octet codant 1 à 7 bits
110xxxxx 10xxxxxx 2 octets codant 8 à 11 bits
1110xxxx 10xxxxxx 10xxxxxx 3 octets codant 12 à 16 bits
11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 4 octets codant 17 à 21 bits
Exemples de codage UTF-8
Car Comment Hex Numérique Binaire Binaire UTF-8
A x41 65 1000001 01000001
Ú xDA 0218 11011010 11000011 10011010
(Monnaie) signe Euro x20AC 8364 10000010101100 11100010 10000010 10101100
𝄞 (Musique) Clé de sol x1D11E 119070 11101000100011110 11110000 10011101 10000100 10011110

Dans la colonne de gauche, on doit voir s’afficher la clef de sol puisque la présente page est en UTF-8 (ce ne serait pas possible en ISO-8859-1 par exemple). Si elle ne s’affiche pas correctement, cela signifie qu’il y a un problème avec votre navigateur13.

Avantages
Inconvénients

UTF-16

UTF-16 (UCS-2 transformation format). UTF-16 est un format variable qui permet de représenter avec un mot de 2 octets tout le BMP, et avec 2 mots les autres plans Unicode. UCS-2 est le format ISO correspondant mais fixé à 2 bytes et donc limité aux possibilités du seul BMP. Sur le BMP, voir UCS-4 ci-dessus. En pratique, seul UTF-16 est utilisé.

L’UTF-16 est une solution très satisfaisante si la place mémoire n’est pas un problème primordial. En effet, la grande majorité des caractères Unicode assignés aux langues modernes (donc les caractères les plus fréquemment utilisés) le sont dans le plan multilingue de base et peuvent donc être représentés sur 16 bits

UTF-16 oblige à s’occuper de l’ordre dans lequel se présentent les octets quand il en faut plus d’un. Cela varie avec les différentes unités centrales informatiques ou normes de transmission.

UTF-16 en BE (big endian)
Bits 00000000 000uuuuu xxxxxxyy yyyyyyyy
UTF-16 BE (2 octets) si uuuuu = 00000 xxxxxxyy yyyyyyyy
UTF-16 BE (4 octets) 110110ww wwxxxxxx 110111yy yyyyyyyy
avec wwww = uuuuu - 1 si uuuuu > 00000

UTF-16 en LE (little endian)
Bits 00000000 000uuuuu xxxxxxyy yyyyyyyy
UTF-16 LE (2 octets) si uuuuu = 00000 yyyyyyyy xxxxxxyy
UTF-16 LE (4 octets) wwxxxxxx 110110ww yyyyyyyy 110111yy
avec wwww = uuuuu - 1 si uuuuu > 00000

UTF-32

UTF-32 (UCS-4 transformation format). Encodage sytématiques sur 4 octets, rarement utilisé. Cette formule fixe offre l’avantage de la simplicité mais constitue dans la plupart des cas un considérable gâchi de mémoire.

Identification et prologues

Différents procédés permettent de renseigner l’ordinateur sur l’encodage des données qu’il traite.

XML

Le premier caractère non blanc14 d’un fichier XML doit être le signe “inférieur à” (60 ou x3C). La suite doit correspondre au prologue XML type :

<?xml version="1.0" encoding="ISO-8859-1"?>

Sans indication, le fichier sera censé être en UTF-8.

HTML

L’encodage d’une page Web est à spécifier dans une balise META, qui figure dans l’entête (partie head).

<head> … <meta charset="utf-8"/> … </head>

On peut utiliser l’attribut HTTP-EQUIV au lieu de charset :

<head> … <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> … </head>
BOM et phénomènes étranges

Dans les fichiers de type plain text (simple texte), il est possible d’utiliser le BOM - Byte Order Mark, “marque du sens des octets”. C’est une suite de caractères utilisée en tout début de fichier ou flot de données pour marquer l’endianness d’une chaîne de caractères Unicode encodée en UTF-16 ou UTF-32 et/ou comme marqueur pour indiquer que le texte est encodé en UTF-8, UTF-16 ou UTF-32.

En UTF-16, le BOM est une séquence de deux octets FE FF au début de la chaîne encodée, indiquant que les caractères encodés suivant utilisent l’ordre big-endian ; avec FF FE, ce sera little-endian. La valeur U+FFFE n’est PAS un caractère Unicode, et peut-être utilisée pour detecter l’ordre des octets, à l’inverse de U+FEFF qui est un caractère connu.

Encodage Séquence BOM
UTF-8EF BB BF
UTF-32, big-endian00 00 FE FF
UTF-32, little-endianFF FE 00 00
UTF-16, big-endianFE FF
UTF-16, little-endianFF FE
UTF-72B 2F 76 [ 38 | 39 | 2B | 2F | 38 2D ]
UTF-EBCDICDD 73 66 73
SCSU (*)0E FE FF
BOCU-1 (**)FB EE 28
(*) Standard Compression Scheme for Unicode
(**) Binary Ordered Compression for Unicode

Quand un programme a été correctement écrit, le BOM reste invisible de son utilisateur. Sinon, en tête de fichier on voit apparaître quelques signes étranges, comme  pour de l’UTF-8 ou þÿ pour l’UTF-16 "big-endian".

Nombre d’éditeurs ou traitements de texte ou autres ajoutent subrepticement la séquence au début des fichiers qui en sont dépourvus. Cependant, sur des systèmes Unix-like (ce qui inclut Linux), qui utilisent beaucoup les fichiers textes pour la configuration, cette technique est dangereuse, car cela peut nuire au traîtement correct de codes importants tels que le hash-bang au début d’un script interprété. Il peut également interférer avec le source pour les langages de programmation qui ne le reconnaissent pas.

Le BOM explique dès lors certains problèmes : ne vous étonnez pas que votre script bash refuse de démarrer alors qu’il commence à première vue par le  #!/bin/bash  réglementaire (et que bash se trouve effectivement dans /bin !) : demandez vous si, à un moment quelconque, il n’a pas été modifié sous Windows. J’ai connu ce cas sur un PC utilisé en dual boot, en jouant entre Windows et Linux.

Entrée des codes au clavier

Ou : comment expérimenter les codes caractère.

Les traîtements de texte sophistiqués, comme Word ou Open Office, fournissent des moyens pour entrer les caractères complexe (accentués, ponctuation, symboles…). Dans d’autres cas (travail sous éditeur de texte, formulaire Web…), on peut se trouver limité par ce qu’offre le clavier. Mais le moyen existe d’utiliser le code interne pour obtenir en sortie tout caractère connu par l’ordinateur. Par exemple pour le O majuscule défini par la valeur 79 (x4F) dans la table ASCII, on peut utiliser la séquence : [Alt]+79 (frapper 79 tout en ayant la touche Alt enfoncée).

Quelques caractères indispensables en français (attention à bien entrer le zéro initial quand il est spécifié) :


Il est rare que la touche Maj tombe en panne. Le procédé s’impose évidemment plutôt pour des caractères non prévus au clavier. Ainsi le code 0223 (xDF) permet d’avoir le "s gothique" (ß) cher aux germanophones. Attention : il faut entrer 0223 (quatre caractères) et non pas 223. Avec 0161 on aura le point d’exclamation inversé (xA1) que les espagnols placent en début d’une phrase terminée par le "!". Idem avec 168 (xBF) pour le point d’interrogation. On a ajouté les voyelles avec accent aigu, indispensables aussi en espagnol et d'autres langues. Cela permettra, par exemple, d’écrire correctement Málaga ou Sándor Márai.


Divers utilitaires et notes de programmation

Commandes
Commande iconv

iconv permet de sortir dans un encodage voulu des données encodées différemment lues en entrée.

Il s’agit d’une commande UNIX/LINUX. Les adeptes de ces pages savent qu’elle s’appliquera sans difficulté sur un système Windows grâce à Cygwin [http://www.dg77.net/tekno/manuel/cygwin.htm]. Voir des applications :

Langages de programmation
Langage Java

Java traîte les données en UNICODE. Des méthodes standard permettent de gérer les entrées et sorties dans d’autres encodages :

Langage REXX

Petit outil d’affichage (cf programme complet) :

/* REXX */
  say " Caractere ? " ; parse pull caract
  say 'Hexadecimal : ' c2x(caract)
  say 'Decimal     : ' c2d(caract)
  say 'Binaire     : ' x2b(c2x(caract))

Application :

15:23:00,02>call bin\conv_hdb.rex
 Caractere ?
Ô
Hexadecimal :  E2
Decimal     :  226
Binaire     :  11100010

Les fonctions SYSTOUNICODE et SYSFROMUNICODE permettent de convertir une chaîne de caractère en unicode à partir d’un autre encodage, et vice-versa. On trouvera dans ces pages un exemple de programme les utilisant, ainsi qu’un cas ou la distinction little/big endian est nécessaire. Cf Generateur RSS à partir d’un fichier texte.

    ZONESORTIE.='NUL'; ZONESORTIE.0=0
    /* Convertir en UNICODE la zone "entree" codee UTF-8 */
    err = systounicode(entree, 'UTF8', , ZONESORTIE.)
    if err == 0 then sortie = ZONESORTIE.!TEXT
                else sortie = 'probleme car. ' || err
    …
      /* Insertion d’espaces en UTF-16 */
    DO travl/2
      tampon = tampon || '2000'x
      /* 0x2000 : octet de poids faible au début : 
      little endian, bon pour processeurs x86 */
    END
Systèmes
IBM AS/400 iSeries

Cf supra EBCDIC, CCSID et Cie.

MS Windows : invite de commande et sorties batch

Par défaut, les caractères sont censés être codés en CP850 (cf supra), ce qui donne un affichage déplorable de nos chers caractères accentués. Le problème se solutionne en appliquant la commande chcp 1252. Avec CP855, un Russophone verra apparaître son texte en cyrillique — sous réserve que sa console utilise une police adéquate.

Exemple avec quelques touches du clavier AZERTY français, qu’on a écrites dans un petit fichier (div.txt). Au départ, on est par défaut en CP850.

13:44:01,33>chcp
Page de codes active : 850
13:44:14,46>type div.txt
&Ú"'(-Þ_þÓ)=^$¨*,;:!¿ ú%Á?./º
13:44:25,56>chcp 1252
Page de codes active : 1252
13:44:31,29>type div.txt
&é"'(-è_çà)=^$ù*,;:!¨ £%µ?./§

Pour ses sauvegardes, votre serviteur utilise entre autres un script batch. Comme l’éditeur sous lequel il est maintenu est toujours paramétré avec encodage en UTF-8, les premières lignes se présentent ainsi :

@echo off
:: Affichage correct des caractères accentués 
:: (65001 page de code pour UTF-8)
chcp 65001 > nul

L’envoi vers NUL de la sortie informative « Page de codes active etc. » empêche cette dernière de s’afficher (ce qui est sinon le cas même avec la clause ECHO OFF) qui précède.

Éditeurs
Éditeur Jext

Edit > Options > Editor > File encoding > Choisir la page de code

En chosissant ensuite Apply, le fichier sera enregistré avec le nouvel encodage à la prochaine mise à jour sur disque (Save, ou Save as…).

Éditeur Jedit

Jedit peut déterminer automatiquement l’encodage à l’ouverture d’un fichier. Si le résultat n’est pas satisfaisant, on peut faire ce qui suit :

Fichier > Recharger avec encodage > Choisir…

Paramétrage de base : Utilitaires > Jedit > Encodages.

On choisit alors le séparateur et l’encodage par défaut. On peut aussi agir sur la reconnaissance automatique de l’encodage et sur le BOM etc.

Éditeur VIM

VI/VIM cherche automatiquement l’encodage du fichier qu’on ouvre. À la sortie, il reste possible de préciser l’encodage. Exemple pour sortir en UTF-8 : set fileencodings=utf-8

Noter les options suivantes :

fileencoding
Encodage du fichier en cours.
inputencoding
Encodage des caractères entrés au clavier.

Notes