logo le blog invivoo blanc

Résoudre vos problèmes d’encodage Unicode

10 juin 2019 | Big Data | 0 comments

INTRODUCTION

L’encodage des caractères est quelque chose de transparent pour la plupart des utilisateurs. C’est même devenu tellement transparent avec l’avènement de l’astucieux format Unicode UTF-8 que même un programmeur peut se retrouver un peu perdu lorsqu’une incompatibilité survient. 

1. QU’EST-CE QUE L’ENCODAGE ?

Une chaîne de caractères n’est pas stockée en mémoire sous forme de chaîne de caractères mais plutôt sous forme de 0 et de 1 binaires.

La représentation la plus lisible pour nous de ce code binaire est l’hexadécimal. Chaque octet représente un unique caractère en ASCII ou en ASCII étendu.

Exemple :

La chaîne suivante, encodée en Windows-1252,
“L’expérience est le nom que chacun donne à ses erreurs.” Oscar Wilde
est représentée comme suit en hexadécimal :

22 4C 27 65 78 70 E9 72 69 65 6E 63 65 20 65 73 “L’expérience es
74 20 6C 65 20 6E 6F 6D 20 71 75 65 20 63 68 61 t le nom que cha
63 75 6E 20 64 6F 6E 6E 65 20 E0 20 73 65 73 20 cun donne à ses
65 72 72 65 75 72 73 2E 22 20 4F 73 63 61 72 20 erreurs.” Oscar
57 69 6C 64 65 Wilde

 

Le 7e caractère “é” est stocké en mémoire avec la valeur hexadécimale “E9” .

Dans la table de caractères Windows-1252, le code “E9” correspond bien au caractère français “é” :

Windows-1252 (CP1252)
x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF
0x NUL SOH STX ETX EOT ENQ ACK BEL BS HT LF VT FF CR SO SI
1x DLE DC1 DC2 DC3 DC4 NAK SYN ETB CAN EM SUB ESC FS GS RS US
2x SP ! # $ % & ( ) * + , . /
3x 0 1 2 3 4 5 6 7 8 9 : ; < = > ?
4x @ A B C D E F G H I J K L M N O
5x P Q R S T U V W X Y Z [ \ ] ^ _
6x ` a b c d e f g h i j k l m n o
7x p q r s t u v w x y z { | } ~ DEL
8x ƒ ˆ Š Œ Ž
9x ˜ š œ ž Ÿ
Ax NBSP ¡ ¢ £ ¤ ¥ ¦ § ¨ © ª « ¬ ® ¯
Bx ° ± ² ³ ´ µ · ¸ ¹ º » ¼ ½ ¾ ¿
Cx À Á Â Ã Ä Å Æ Ç È É Ê Ë Ì Í Î Ï
Dx Ð Ñ Ò Ó Ô Õ Ö × Ø Ù Ú Û Ü Ý Þ ß
Ex à á â ã ä å æ ç è é ê ë ì í î ï
Fx ð ñ ò ó ô õ ö ÷ ø ù ú û ü ý þ ÿ

 

Pourtant, si vous allez dans une fenêtre MS-DOS, le code hexadécimal “E9” ne va pas s’afficher correctement !

En effet, la fenêtre MS-DOS affiche :

Cd \temp
Type test.txt
“L’expÚrience est le nom que chacun donne Ó ses erreurs.” Oscar Wilde

Car MS-DOS considère par défaut que les textes (sur un poste français) sont encodés avec la page 850 ci-dessous :

page 850 (DOS latin-1)
x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF
0x NUL SOH STX ETX EOT ENQ ACK BEL BS HT LF VT FF CR SO SI
1x DLE DC1 DC2 DC3 DC4 NAK SYN ETB CAN EM SUB ESC FS GS RS US
2x SP ! # $ % & ( ) * + , . /
3x 0 1 2 3 4 5 6 7 8 9 : ; < = > ?
4x @ A B C D E F G H I J K L M N O
5x P Q R S T U V W X Y Z [ \ ] ^ _
6x ` a b c d e f g h i j k l m n o
7x p q r s t u v w x y z { | } ~ DEL
8x Ç ü é â ä à å ç ê ë è ï î ì Ä Å
9x É æ Æ ô ö ò û ù ÿ Ö Ü ø £ Ø × ƒ
Ax á í ó ú ñ Ñ ª º ¿ ® ¬ ½ ¼ ¡ « »
Bx Á Â À © ¢ ¥
Cx ã Ã ¤
Dx ð Ð Ê Ë È ı Í Î Ï ¦ Ì
Ex Ó ß Ô Ò õ Õ µ þ Þ Ú Û Ù ý Ý ¯ ´
Fx SHY ± ¾ § ÷ ¸ ° ¨ · ¹ ³ ² NBSP

Le caractère hexadécimal “E9” correspond au caractère “Ú” en encodage page 850 et non au caractère “é” que nous attendions.

On comprend ainsi qu’un fichier texte est en fait un message codé (et non pas chiffré) qu’il convient de le décoder avec une table de traduction précise (l’encodage).

La difficulté est donc double :

– Il faut bien choisir, en fonction de l’application cible, l’encodage à utiliser lorsque l’on sauvegarde un texte.
– Il faut être capable au moment de la restitution du texte (de son affichage) de déterminer l’encodage à utiliser.

Le blog INVIVOO est en encodage UTF-8. Mais si vous vous amusiez à forcer l’utilisation de l’encodage ISO-8859-7 dans Internet Explorer avec le menu “View => Encoding => More => Greek (ISO)” alors les caractères windows-1252 suivants :

x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF
Fx ð ñ ò ó ô õ ö ÷ ø ù ú û ü ý þ ÿ

 

s’afficheraient comme suit :

x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF
Fx Γ° Γ± Γ² Γ³ Γ΄ Γ΅ ΓΆ Γ· ΓΈ ΓΉ ΓΊ Γ» ΓΌ Γ½ ΓΎ ΓΏ

On constate que les caractères occidentaux attendus s’affichent, maintenant, mal et qu’ils sont sur deux caractères au lieu d’un seul.

C’est parce qu’en encodage unicode UTF-8 les caractères spéciaux occidentaux sont tous codés sur deux octets. Et parce que l’encodage ISO-8859-7 (Grec) considère que chacun de ces deux octets est un caractère en lui-même dans sa table de mapping.

A noter que le nombre d’encodage différents existant est relativement important. C’est parce que l’histoire de l’encodage leur porte tous une raison d’être précise. A mesure de l’internationalisation induite par le web, la gestion des encodages pouvait devenir rapidement très complexe à gérer du fait des environnements multilingues.

Heureusement, l’encodage Unicode a réussi le défi de réunir tous les caractères de tous les encodages dans une seule et même table de caractères.

 

2. LE FORMAT UTF-8

Le format Unicode est né de la volonté d’unifier la multitude des codes existants. La multiplicité des codes était nécessaire car les systèmes ont toujours considéré qu’un octet correspondait à un seul caractère. Or, un octet ne permet de coder que 256 caractères. Certains langages avaient donc besoin de leur propre code. Le “é” français n’est par exemple pas du tout utile pour les grecs qui ont d’ailleurs besoin de coder tout un alphabet qui leur est propre.

La solution Unicode est de s’affranchir de l’octet unique pour avoir une quantité virtuellement infinie de caractères. Les caractères asiatiques peuvent être codés par exemple avec 4 octets.

Malheureusement, il existe plusieurs versions du format Unicode selon que le nombre d’octets par caractère est fixe ou dynamique, et selon l’ordre de lecture des octets.

Nous allons présenter uniquement le format UTF-8 car il a tendance à s’imposer du fait de son efficacité en terme taille mémoire et du fait de sa rétrocompatibilité avec l’ASCII. En effet, rien ne distingue un vieux fichier ASCII d’un fichier UTF-8. C’est seulement lorsqu’on utilise des caractères spéciaux que le fichier UTF-8 va se distinguer de l’ASCII.

Les caractères spéciaux en UTF-8 seront stockés en hexadécimal sur 2 à 4 octets en respectant tout simplement la table de caractères UTF-8. Quelque part, c’est toujours aussi simple qu’avant : A un “code” correspond toujours un seul caractère dans la table.

Si une application ne sait pas lire l’UTF-8 ou bien si elle est forcée en ASCII étendu (comme dans notre exemple précédent sur le forçage en ISO-8859-7 dans internet explorer) alors l’application va lire chaque octet comme seul et unique caractère. Or les caractères spéciaux d’Europe de l’ouest sont tous codés sur deux octets en UTF-8.

=> C’est pour cette raison que les accents sont affichés sur deux caractères au lieu d’un seul lorsque l’encodage est mal déterminé.

A ce stade, coici les principales informations à retenir sur l’UTF-8 :

– C’est retro-compatible avec l’ASCII, 
– Les caractères spéciaux sont stockés sur deux à quatre octets, 
– Comme tout encodage, il faut que l’application qui “lit” le code hexadécimal utilise le bon encodage. 

Pour tout savoir, il ne reste qu’une particularité de l’Unicode qui pose encore des problèmes de compatibilité : le BOM (Byte Mark Order). Nous allons en parler dans la partie suivante.

 

3. LES PROBLEMES D’ENCODAGE PERSISTANTS

Après cette présentation nécessaire des encodages texte, on aborde enfin le point central de cet article avec la question suivante :

Si UTF-8 possède tous les caractères et peut remplacer tous les codes, pourquoi rencontre-t-on encore des problèmes d’encodage ???

1. Le changement prend du temps

La principale raison est que les vieux systèmes n’ont pas forcément évolué en même temps que la révolution Unicode. Ainsi, il peut y avoir des bases de données, des applications ou des progiciels qui avaient été programmés pour recevoir un encodage bien particulier et surtout avec un seul octet par caractère.

2. La spécificité de Microsoft Windows

Microsoft a pris la liberté de créer ses propres tables de caractères dérivées des tables ISO-8859-x. De plus, il est impossible de savoir si un texte utilise une table ISO ou Windows car elles correspondent toutes les deux à des suites d’octets.

Cette liberté prise par Microsoft serait moins gênante si les applications Windows utilisaient l’UTF-8 par défaut mais ce n’est pas le cas. Sans caractère spéciaux en dehors de la table Windows-1252, la plupart des applications windows n’enregistre pas en UTF-8 par défaut.

Ainsi, envoyer un fichier texte Windows sur un serveur linux ou une application propriétaire peut mener à des confusions très facilement.

3. Les polices de caractères

Du fait que l’Unicode permet de coder l’ensemble des caractères possibles, c’est devenu un cauchemar pour les artistes créant des polices de caractères car redessiner chaque caractère est une tâche colossale. Et ils ne le font d’ailleurs pas afin de se concentrer sur le langage qui les intéresse. Par ailleurs, le standard Unicode peut rajouter de nouveaux caractères dans la table et des polices existantes deviennent ainsi incomplètes !

Ainsi, pour les langages très exotiques, il peut être nécessaire de travailler avec des polices spécifiques.

Cependant, les polices de caractères n’affectent que l’affichage et en aucun cas ne perturbent vos traitements ou le stockage en base de données de vos chaînes de caractères.

4. Le BOM (Byte Order Mark)

Le Byte Order Mark est une suite d’octets Unicode non imprimables placés au début d’un texte Unicode afin de faciliter son interprétation. Ce Byte Order Mark n’est pas standard, ni obligatoire mais facilite la lecture par les applications compatibles afin de déterminer le type de format Unicode et le sens de lecture des octets.

Cela pose souvent des problèmes de compatibilité car toutes les applications ne savent pas gérer le « BOM ». Pour les applications non compatibles, cette suite d’octets est considérée comme des caractères normaux en ASCII étendu. Dans le cas d’un fichier UTF-8 lu, à tort, comme du Windows-1252, on verrait 3 caractères étranges tout au début du fichier : .

Les caractères  correspondent à la chaîne hexadécimale EF BB BF qui est un code pour indiquer aux applications compatibles que le fichier est un fichier Unicode au format UTF-8.

Un autre problème du BOM est la confusion qu’il peut apporter à un utilisateur. EF BB BF correspond à des caractères non imprimables en UTF-8. Du coup, dans un éditeur de texte Unicode, il est difficile de savoir si le BOM a été appliqué ou pas puisqu’il est invisible et en plus optionnel dans un fichier UTF-8. Beaucoup d’utilisateurs ne savent d’ailleurs certainement pas ce qu’est le BOM et comment il peut faire planter des applications non compatibles en aval.

Et pire, il existe plusieurs BOM possibles pour indiquer des formats Unicode différents de UTF-8 et généralement encore moins compatibles.

Comme le BOM est invisible pour l’utilisateur, la confusion est évidente et inévitable.

Cependant, dans la section ci-dessous, nous allons vous fournir des outils standards afin de pouvoir rapidement déterminer si votre fichier est tel que vous l’attendiez.

 

5. DETERMINER L’ENCODAGE D’UN FICHIER TEXTE

Quelle que soit l’origine d’un fichier, qu’il soit généré automatiquement, qu’il soit envoyé par un fournisseur de données, ou que vous l’ayez construit manuellement, il peut être utile de vérifier avec certitude son format et son éventuel tag BOM.

Si vous n’avez pas accès à des éditeurs de texte évolués (et généralement payant), vous pouvez le faire facilement avec des éditeurs hexadécimal standard sur Windows et sur Linux.

Sur Windows :
– Touche windows+R
– Commande powershell
– Cd \temp
– Fhx test.txt

Sur Linux :
cd /home/test/
file -bi test.txt
=> Linux “essaye” de vous afficher le format du fichier mais pour voir vous-même le tag BOM il faut faire la commande :
xxd test.txt

S’il y a un tag BOM au tout début du fichier alors c’est un texte au format Unicode :
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

Surtout, souvenez-vous que l’absence du tag BOM ne veut pas dire que le fichier n’est pas un fichier Unicode.

Bien au contraire, il peut être nécessaire de le supprimer pour augmenter la compatibilité avec vos applications.

Maintenant, nous allons voir comment supprimer le BOM en VBA pour éviter de faire planter des applications en aval.

 

5. EXERCICE AVANCÉ EN VBA

Lorsque vous créez un fichier Unicode avec des Macro VBA à destination d’applications sensibles au format, vous rencontrerez probablement des difficultés pour maîtriser le BOM.

Pour commencer, vous pouvez utiliser les commandes proposées dans la partie précédente pour vérifier vos fichiers de sortie.

Pour créer des fichiers UTF-8 à votre convenance, avec ou sans Byte Order Mark, il faut connaitre ces limitations de VBA :

1. La commande Print #1 ne permet pas d’enregistrer en UTF-8, vous perdez vos caractères Unicode
Exemple :
Open “c:\Temp\test.txt” For Output As #1
Print #1, “Ligne 1 : un caractère très spécial Unicode : Ж = D0 96”

2. La commande SavetoFile des objets “ADODB.Stream” crée toujours un BOM EF BB BF sur les fichiers UTF-8 ! Ne cherchez pas : il n’y a pas d’option pour écrire un UTF-8 sans BOM mais nous allons vous donner une solution.

Connaître ces deux limitations va vous économiser de longues recherches.

Ci-dessous un exemple de code vous permettant de créer deux fichiers : avec BOM EF BB BF et sans BOM.

Sub Créer_UTF8()

Dim lStreamUTF8BOM, lStreamBinaireSansBOM As Object
Set lStreamUTF8BOM = CreateObject(“ADODB.Stream”)
Set lStreamBinaireSansBOM = CreateObject(“ADODB.Stream”)

‘On crée le flux maître
lStreamUTF8BOM.Type = 2 ‘2 = Type Texte
lStreamUTF8BOM.Mode = 3 ‘3 = Mode Lecture et Ecriture
lStreamUTF8BOM.Charset = “UTF-8” ‘format Unicode UTF-8 avec BOM
lStreamUTF8BOM.Open

lStreamUTF8BOM.WriteText “Ligne 1 : un caractère très spécial Unicode : Ж = D0 96” & vbCrLf
lStreamUTF8BOM.WriteText “Ligne 2” & vbCrLf

‘sauvegarde UTF-8 avec BOM
lStreamUTF8BOM.SaveToFile “c:\Temp\UTF8avecBOM.txt”, 2 ‘2 = overwrite

‘sauvegarde UTF-8 sans BOM
lStreamBinaireSansBOM.Type = 1 ‘1 = binaire
lStreamBinaireSansBOM.Mode = 3 ‘3 = Mode Lecture et Ecriture
lStreamBinaireSansBOM.Open
lStreamUTF8BOM.Position = 3
lStreamUTF8BOM.CopyTo lStreamBinaireSansBOM

lStreamBinaireSansBOM.SaveToFile “c:\Temp\UTF8sansBOM.txt”, 2 ‘2 = overwrite
lStreamBinaireSansBOM.Flush
lStreamBinaireSansBOM.Close
lStreamUTF8BOM.Flush
lStreamUTF8BOM.Close

End Sub

Pour vérifier les résultats, vous pouvez ouvrir les fichiers dans C:\TEMP\ avec Powershell et la commande fhx comme indiqué dans la section précédente.

 

CONCLUSION

Nous vous avons présenté comment fonctionnent les encodages et ce qu’apporte la révolution du format UTF-8.

Cependant des incompatibilités d’encodage peuvent persister ponctuellement entre applications alors nous vous avons proposé des outils pour vérifier le format de vos fichiers et notamment consulter l’invisible Byte Order Mark. Par ailleurs, vous savez maintenant comment créer des fichiers UTF-8 avec ou sans BOM via VBA.

Vous avez maintenant tous les outils pour aider aux diagnostics de vos éventuels problèmes d’encodage et uniquement avec l’aide d’outils standards !