Développons En Java - L'encodage Des Caractères - Jmdoudoux
Maybe your like
| Niveau : | |
Un caractère est une unité minimale abstraite de texte qui n'a pas forcément toujours la même représentation graphique.
La plate-forme Java utilise Unicode pour son support des caractères mais il est fréquent de devoir traiter des données textuelles encodées différemment en entrée ou en sortie d'une application. Java propose plusieurs classes et méthodes pour permettre la conversion de nombreux encodages de caractères de et vers Unicode.
Les applications Java qui doivent traiter des données non encodées en Unicode, sont lues avec l'encodage adéquat, stockées et traitées en Unicode et exportent le résultat de Unicode vers l'encodage initial ou l'encodage cible.
La version 5.0 de Java propose un support de la version 4.0 d'Unicode.
La JSR 204 « Unicode Supplementary Character Support » définit le support des caractères étendus d'Unicode dans la plate-forme Java. Ceci permet le support des caractères au-delà des 65546 possibles sur un stockage dans 2 octets.
Ce chapitre contient plusieurs sections :
- L'utilisation des caractères dans la JVM
- Les jeux d'encodages de caractères
- Unicode
- L'encodage de caractères
- L'encodage du code source
- L'encodage de caractères avec différentes technologies
108.1. L'utilisation des caractères dans la JVM
Une chaîne de caractères est stockée en interne dans la JVM en UTF-16. L'encodage des caractères est uniquement à réaliser en entrée ou en sortie de la JVM (fichiers, base de données, flux, ...).
108.1.1. Le stockage des caractères dans la JVM
En interne, Java utilise le jeu de caractères Unicode et stocke les caractères encodés en UTF-16. Cependant pour le stockage persistant ou l'échange de données, il peut être nécessaire d'utiliser différents jeux d'encodages de caractères. Java propose des mécanismes au travers d'API pour permettre ces conversions.
Le type de données primitif char qui stocke un caractère a une représentation sous la forme d'un entier de 16 bits non signé pour pouvoir contenir un caractère encodé en UTF-16. Toutes les classes qui encapsulent un ou plusieurs caractères encodent ceux-ci en UTF-16 en interne dans la JVM.
108.1.2. L'encodage des caractères par défaut
Pour modifier l'encodage utilisé par défaut pour la lecture et l'écriture dans des flux, il faut modifier la valeur de la propriété file.encoding de la JVM.
Il est possible de fournir la valeur désirée en paramètre de la JVM.
| Exemple : |
La propriété peut aussi être modifiée par programmation en utilisant la méthode setProperty() de la classe System.
| Exemple : |
108.2. Les jeux d'encodages de caractères
Il existe de nombreux jeux d'encodages de caractères. Une liste complète des jeux d'encodages de caractères est consultable à l'url https://www.iana.org/assignments/character-sets
Un jeu de caractères est un ensemble de caractères. Dans un jeu, chaque caractère est associé à une valeur unique.
Les jeux de caractères les plus utilisés dans les pays occidentaux sont notamment ISO-8859-1, ISO-8859-15, UTF-8, Windows CP-1252, ...
108.3. Unicode
Unicode est un ensemble de caractères pouvant contenir tous les caractères utilisés dans le monde. Unicode peut contenir jusqu'à 1 million de caractères, mais tous les caractères ne sont pas utilisés.
L'ensemble des caractères est divisé en blocs.
Unicode est géré par un consortium : la version courante d'Unicode est la 5.
Unicode attribue à chaque caractère un identifiant nommé code point. Unicode utilise la notation hexadécimale prefixée par « U+ » pour représenter un code point : exemple avec le caractère A qui possède le numéro U+0041.
Les 127 premiers caractères d'Unicode correspondent exactement à l'ensemble des caractères Ascii.
108.3.1. L'encodage des caractères Unicode
Les caractères Unicode peuvent être encodés avec plusieurs encodages de la norme UTF (Unicode Transformation Format)
UTF-32 est l'encodage le plus simple d'Unicode puisqu'il utilise 32 bits (4 octets) pour stocker chaque caractère mais c'est aussi l'encodage le plus coûteux en mémoire.
UTF-16 utilise un encodage sur 16 bits (2 octets) ou 2 fois 16 bits pour stocker les caractères Unicode. Ainsi les valeurs comprises entre U+0000 et U+FFFF sont encodées uniquement sur 16 bits. Les valeurs au-delà sont stockées sur 2 fois 16 bits. Son principal avantage est qu'il est capable de stocker la plupart des caractères courants avec un seul entier de 16 bits.
Remarque : les fichiers encodés en UTF-16 ne sont généralement pas échangeables entre différents systèmes car deux conventions d'ordonnancement des octets sont utilisées.
UTF-8 utilise un encodage sur 1 à 4 octets pour stocker les caractères Unicode selon leurs valeurs :
- entre U+0000 et U+007F : elles sont stockées sur un seul octet
- entre U+0080 et U+07FF : elles sont stockées sur deux octets
- entre U+0800 et U+FFFF : elles sont stockées sur trois octets
- entre U+10000 to U+10FFFF : elles sont stockées sur quatre octets
Avec UTF-8 chaque caractère est encodé sur un nombre variable d'octets. L'avantage d'UTF-8 est qu'il est compatible avec l'Ascii puisque les premiers caractères sont ceux de la table Ascii et qu'ils sont codés sur un seul octet en UTF-8. Ceci rend UTF-8 assez largement utilisé.
L'encodage/décodage en UTF-8 est assez coûteux car complexe puisque les caractères sont encodés sur un nombre variable d'octets.
UTF-7 encode un caractère Unicode grâce à des séquences de caractères Ascii 7 bits. Cet encodage est utilisé par certains protocoles de messagerie.
Le tableau ci-dessous montre les valeurs des octets de différents encodages de quelques caractères Unicode.
| Symbole | A | Z | 0 | 9 | € | é | @ |
| Code point | U+0041 | U+005A | U+0030 | U+0039 | U+20AC | U+00E9 | U+0040 |
| UTF-8 | 41 | 5A | 30 | 39 | E2 82 AC | C3 A9 | 40 |
| UTF-16 Litte endian | 41 00 | 5A 00 | 30 00 | 39 00 | AC 20 | E9 00 | 40 00 |
| UTF-16 Big endian | 00 41 | 00 5A | 00 30 | 00 39 | 20 AC | 00 E9 | 00 40 |
| UTF-32 Little endian | 41 00 00 00 | 5A 00 00 00 | 30 00 00 00 | 39 00 00 00 | AC 20 00 00 | E9 00 00 00 | 40 00 00 00 |
| UTF-32 Big endian | 00 00 00 41 | 00 00 00 5A | 00 00 00 30 | 00 00 00 39 | 00 00 20 AC | 00 00 00 E9 | 00 00 00 40 |
108.3.2. Le marqueur optionnel BOM
Le début d'un fichier encodé en UTF peut contenir un marqueur optionnel nommé BOM (Byte Order Marker). Ce marqueur a deux utilités :
- Permettre de préciser que le texte est encodé en UTF-8, UTF-16 ou UTF-32
- Pour UTF-16- et UTF-32, il permet de préciser l'ordre des octets (little-endian ou big-endian)
En UTF-8, les trois premiers octets du BOM sont EF BB BF.
Lorsque l'on édite un fichier encodé en UTF-8 contenant un BOM avec un éditeur utilisant l'encodage iso-8859-1, les premiers octets affichés sont �»�.
En UTF-16, les deux premiers octets du BOM peuvent avoir deux valeurs :
- FE FF : pour un big-endian
- FF FE : pour un little-endian
En UTF-32, les quatre premiers octets du BOM peuvent avoir deux valeurs :
- 00 00 FE FF : pour un big-endian
- FF FE 00 00 : pour un little-endian
108.4. L'encodage de caractères
L'environnement d'exécution Java supporte en standard plusieurs jeux d'encodages de caractères dont :
- US-ASCII : encodage des caractères sur 7 bits
- ISO-8859-1 (latin 1) : encodage des caractères sur 8 bits dans un seul octet pour la plupart des caractères des langues européennes de l'ouest excepté le caractère €
- ISO-8859-15 : comme l'ISO-8859-1 sauf 8 caractères qui sont différents dont le caractère €
- UTF-8 : encodage des caractères sur 8 bits dans 1 à 4 octets. Les caractères ASCII correspondent aux premiers caractères en UTF-8. Peut commencer par un ensemble d'octets optionnels nommés BOM (EF BB BF)
- UTF-16 : encodage des caractères sur 16 bits dans 2 ou 4 octets. Il permet l'encodage de tous les caractères utilisés dans le monde (deux encodages existent : UTF-16 BE et UTF-16 LE)
- Cp1252 : variante utilisée par Microsoft Windows du latin 1
- ...
Les implémentations de l'environnement d'exécution Java proposent généralement un ensemble beaucoup plus complet de jeux d'encodages de caractères.
Plusieurs classes qui manipulent des caractères permettent de convertir les caractères au format Unicode en utilisant le jeu d'encodages de caractères souhaité notamment :
- java.lang.String
- java.io.InputStreamReader
- java.io.OutputStreamWriter
- et les classes du package java.nio.charset
Les jeux d'encodages de caractères supportés par la plate-forme Java dépendent de leurs implémentations. Les jeux de caractères supportés en standard sont stockés dans le fichier rt.jar
Attention : la désignation des jeux de caractères dans les API java.io et java.lang est différente de la désignation de ceux de l'API java.nio. Exemple :
| Description | Nom pour l'API java.io et java.lang | Nom pour l'API java.nio |
| MS-DOS Latin-2 | Cp852 | IBM852 |
| ISO Latin 1 | ISO8859_1 | ISO-8859-1 |
| ISO Latin 2 | ISO8859_2 | ISO-8859-2 |
| ISO Latin 15 | ISO8859_15 | ISO-8859-15 |
| ASCII | ASCII | US-ASCII |
| UTF 8 | UTF8 | UTF-8 |
| UTF 16 | UTF-16 | UTF-16 |
| UTF 32 | UTF_32 | UTF-32 |
| Windows Latin 1 | Cp1252 | windows-1252 |
Les jeux de caractères supportés par la version internationale sont dans le fichier charsets.jar du sous-répertoire lib du répertoire d'installation du JRE.
Le plus important lorsque l'on manipule des données de type texte en Java est de s'assurer que les caractères seront encodés ou décodés avec le bon jeu de caractères d'encodage.
Une fois que la conversion est faite en écriture et en lecture, le support des caractères Unicode se fera de façon transparente entre l'application Java et les ressources externes.
Par exemple, pour écrire des données de type texte dans un fichier, il suffit de préciser le jeu de caractères d'encodage. Lors de la lecture de ce fichier, il suffit de préciser le même jeu de caractères d'encodage pour obtenir les données.
Chaque fichier encodé est composé d'un ensemble d'un ou plusieurs octets. Java travaille en interne en stockant les données de types caractères ou chaîne de caractères en Unicode en utilisant l'encodage UTF-16.
L'encodage se fait toujours du type String vers le type byte[].
Le décodage se fait toujours du type byte[] vers le type String.
108.4.1. Les classes du package java.lang
La classe String permet aussi des conversions d'Unicode vers un type d'encodage et vice versa.
Un constructeur de la classe String permet de créer une chaîne de caractères à partir d'un tableau d'octets et du nom de l'encodage utilisé.
| Exemple : |
Pour obtenir un tableau d'octets qui contient le contenu d'une chaîne de caractères encodée selon un encodage particulier, il faut utiliser la méthode getBytes() de la classe String
| Exemple : |
La méthode getBytes() de la classe String utilise par défaut l'encodage du système d'exploitation sur lequel la JVM est exécutée.
Une surcharge de la méthode getBytes() permet de préciser l'encodage à utiliser.
108.4.2. Les classes du package java.io
Les classes qui héritent des classes Reader et Writer proposent des fonctionnalités pour permettre des opérations de lecture et d'écriture de caractères dans un flux.
La classe InputStreamReader permet de lire des données encodées avec de nombreux types d'encodage pour obtenir des données stockées dans la JVM en Unicode.
| Exemple : |
La classe OutputStreamReader permet d'écrire des données en Unicode encodées vers de nombreux types d'encodage.
Les classes qui héritent de la classe Reader décodent des octets en String en fonction de l'encodage précisé.
Les classes qui héritent de la classe Writer encodent des String en octets en fonction de l'encodage précisé.
Les classes FileReader et FileWriter permettent de lire et d'écrire des caractères dans un flux.
| Exemple : |
108.4.3. Le package java.nio
Le package java.nio.charset propose plusieurs classes pour réaliser des conversions de caractères.
La méthode canEncode() de la classe CharsetEncoder permet de vérifier si une chaîne de caractères peut être encodée avec un jeu de caractères d'encodage.
| Exemple : vérifier si une chaîne de caractères peut être encodée en latin-1 |
La méthode availableCharsets() de la classe java.nio.Charset permet de connaître la liste des encodages supportés.
La classe java.nio.Charset permet aussi de faire des conversions. Son grand avantage est de ne pas avoir à rechercher la classe correspondant à l'encodage utilisée à chaque appel comme c'est le cas avec les méthodes de la classe String.
| Exemple : |
Le package java.nio.charset.spi propose des classes pour définir ses propres jeux d'encodage de caractères.
108.5. L'encodage du code source
La plupart des fichiers sources sont encodés en ASCII, ISO-8859-1 ou autres mais dans tous les cas, ils sont transformés en UTF-16 avant la compilation.
Le code source peut être écrit directement en utilisant un format UTF, par exemple UTF-8. Il suffit alors de préciser au compilateur le jeu de caractères d'encodage utilisé.
Attention : si le code est écrit en UTF-8, il faut s'assurer que l'éditeur n'inclut pas le BOM (Byte Order Mark) au début du fichier (par exemple, c'est ce que fait l'outil Notepad sous Windows), sinon le compilateur refusera de compiler le code source
| Exemple : |
Avec l'outil Notepad, il faut enregistrer le fichier au format utf-8 et compiler la classe en précisant que l'encodage est UTF-8.
| Exemple : |
En fait, Notepad a ajouté les octets du BOM au début du fichier
| Résultat : |
Sans ces octets, le code source se compile parfaitement sous réserve de bien préciser la valeur utf-8 au paramètre -encoding du compilateur javac.
Il est aussi possible d'utiliser l'outil native2ascii, dont le nom est relativement inadéquat, fourni avec le jdk . Cet outil lit le code source et le convertit en ascii en échappant les caractères non ascii avec leur représentation hexadécimale sous la forme \unnnn, où nnnn représente le code Unicode du caractère. Il n'est alors plus nécessaire d'utiliser le paramètre encoding. L'avantage de cette solution est que le code source est lisible sur tous les systèmes puisqu'il est encodé en Ascii.
108.6. L'encodage de caractères avec différentes technologies
L'encodage de caractères est généralement nécessaire et cela avec plusieurs technologies utilisées en Java.
108.6.1. L'encodage de caractères dans les fichiers
Généralement, les fichiers texte ne contiennent aucunes indications sur l'encodage utilisé.
Certaines normes proposent cependant des fonctionnalités optionnelles pour fournir l'information.
| Exemple : HTML |
| Exemple : XML |
108.6.2. L'encodage de caractères dans une application web
Pour utiliser l'encodage UTF-8 dans une application web, il faut prendre plusieurs précautions.
Dans les JSP, il faut définir l'encodage utilisé
| Exemple : |
Dans une servlet, il est possible d'utiliser la méthode setCharacterEncoding() de la classe HttpRequest pour préciser l'encodage des données de la requête. Cet appel doit être fait avant l'utilisation de la méthode getParameter() pour que les données soit correctement décodées.
108.6.3. L'encodage de caractères avec JDBC
Avec JDBC, il est parfois nécessaire de préciser l'encodage utilisé dans les données échangées. Dans ce cas, l'attribut à utiliser dépend de la base de données concernée et il faut consulter la documentation du pilote JDBC utilisé.
| Exemple : |
Tag » Code Utf 8 Caractères Spéciaux
-
HTML: Liste De Caractères Unicode En UTF-8 - JCHR
-
UTF-8 - Wikipédia
-
HTML XHTML -L'encodage Et Les Caractères Spéciaux - UpyUpy
-
Codage Unicode UTF-8 - EniG. Webmaster Tools
-
Encodages Web Du Caractère « é » Ou « E Accent Aigu »
-
Les Codes D'encodage Du Caractère Spécial « » Ou « Saut De Ligne ».
-
Gestion De L'encodage Des Caractères En HTML Et CSS (tutoriel)
-
Résoudre Vos Problèmes D'encodage Unicode - Invivoo
-
Encodage Des Caractères Spéciaux [
-
Encodage Dans L'URL (UTF-8, Comme Par Exemple %20 Pour Un ...
-
Encodage UTF-8 : Tout Pour Mener Votre Projet à Bien
-
Coder Intégralement En UTF8
-
Encodage Du Jeu De Caractères Dans Les Fichiers De Syntaxe - IBM
-
[PDF] Les Caractères Spéciaux En XML Et HTML : La Norme Unicode