HOWTO Unicode: Comment faire pour que vos programmes comprennent Unicode
5. Comment faire pour que vos programmes comprennent Unicode
5.1 C/C++
Le type C 'char ' est 8-bits et restera 8-bits parce qu'il
désigne la plus petite unité de données adressable. Divers
aménagements sont disponibles :
Pour le traitement de texte normal
Le standard ISO/ANSI C contient, dans une correction qui fut ajoutée
en 1995, un type de caractère codé sur 16 bits
`wchar_t ', un ensemble de fonctions comme celles contenues
dans <string.h> et <ctype.h>
(déclarées respectivement dans <wchar.h> et
<wctype.h> ), et un ensemble de fonctions de conversion
entre `char * ' et `wchar_t * ' (déclarées dans
<stdlib.h> ).
Voici de bonnes réferences pour cette interface de programmation :
Avantages de cette interface de programmation :
- C'est un standard non propriétaire.
- Ces fonctions font ce qu'il faut, selon les locales de
l'utilisateur. Tout ce qu'un programme doit faire est d'appeler
setlocale(LC_ALL,""); .
Inconvénients de cette interface de programmation :
- Certaines de ces fonctions ne sont pas "multithread-safe" parce
qu'elles conservent un état interne caché entre les appels de fonction.
- Il n'y a pas de type de donnée de première classe. Par conséquent
cette API ne peut pas être utilisée raisonnablement pour tout ce qui
nécessite plus d'une locale ou d'un jeu de caractères au même moment.
- La plupart des systèmes d'exploitation ont un mauvais support de
cette interface de programmation.
Notes concernant la portabilité
Une variable `wchar_t ' peut être encodée en Unicode ou non.
Ceci dépend de la plateforme et quelquefois aussi des locales.
Une séquence multi-octets `wchar_t ' peut être encodée en
UTF-8 ou non selon la plateforme, et parfois selon les locales.
En détails, voici ce que la
Single Unix specification
dit à propos du type `wchar_t ' :
Tous les codes de caractères 16 bits dans un processus donné
consistent en un nombre égal de bits. Ceci en contraste avec les
caractères, qui peuvent être constitués d'un nombre variable d'octets.
L'octet ou la séquence d'octets qui représentent un caractère peuvent
aussi être représentés comme un code de caractère 16 bits.
Les codes de caractères 16 bits fournissent donc une taille uniforme
pour manipuler les données textuelles. Un code de caractère 16 bits ayant
tous les bits à 0 est un code de caractère 16 bits nul (null), et
termine une chaîne. La valeur des caractères
larges pour chaque membre du "Portable Character Set" (i.e ASCII) est
égale quand il est utilisé en tant que seul caractère dans un
caractère entier (integer) constant. Les codes de caractères 16 bits
pour les autres caractères dépendent des locales et de
l'implémentation.
Les octets modificateurs d'état n'ont pas de représentation en code de
caractère 16 bits.
Une conséquence notable est que dans des programmes portables vous ne
devriez pas utiliser des caractères non-ASCII dans des chaînes
littérales.
Cela signifie que même si vous savez que les doubles guillemets ont
les codes U+201C et U+201D, vous ne devriez pas écrire une chaîne
littérale L"\u201cBonjour\u201d, dit il" ou
"\xe2\x80\x9cBonjour\xe2\x80\x9d, dit il" dans des programmes
C. Utilisez plutôt GNU gettext comme cela : gettext ("'Bonjour',
dit il") , et créez une base de données de messages en.UTF-8.po
qui traduit "'Bonjour' dit il" en "\u201cBonjour\u201d, dit
il" .
Voici une étude de la portabilité des aménagements ISO/ANSI C sur
diverses implémentations d'Unix. La GNU glibc-2.2 les supportera
tous, mais pour l'instant nous avons le tableau suivant.
- GNU glibc-2.0.x, glibc-2.1.x
- <wchar.h> et <wctype.h> existent.
- Possède les fonctions wcs/mbs, mais pas fgetwc/fputwc/wprintf.
- Pas de locales UTF-8.
- mbrtowc retourne EILSEQ pour les octets >= 0x80.
- Solaris 2.7
- <wchar.h> et <wctype.h> existent.
- Possède toutes les fonctions wcs/mbs, fgetwc/fputwc/wprintf.
- Supporte les locales UTF-8 suivantes : en_US.UTF-8, de.UTF-8,
es.UTF-8, fr.UTF-8, it.UTF-8, sv.UTF-8.
- mbrtowc retourne EILSEQ pour les octets >= 0x80.
- OSF/1 4.0d
- <wchar.h> et <wctype.h> existent.
- Possède toutes les fonctions wcs/mbs, fgetwc/fputwc/wprintf.
- A en plus universal.utf8@ucs4 locale, voir "man 5 unicode".
- mbrtowc ne connaît pas UTF-8.
- Irix 6.5
- <wchar.h> et <wctype.h> existent.
- Possède les fonctions wcs/mbs et fgetwc/fputwc,
mais pas wprintf.
- N'a pas de locales multi-octets.
- A seulement un simulacre de définition pour mbstate_t.
- N'a pas mbrtowc.
- HP-UX 11.00
- <wchar.h> existe, mais pas <wctype.h>.
- Possède les fonctions wcs/mbs et fgetwc/fputwc,
mais pas wprintf.
- A une locale C.utf8.
- N'a pas mbstate_t.
- N'a pas mbrtowc.
- AIX 4.2
- <wchar.h> existe, mais pas <wctype.h> - utilisez
à la place <ctype.h> et <wchar.h>.
- Possède les fonctions wcs/mbs et fgetwc/fputwc,
mais pas wprintf.
- Possède les locales UTF-8 suivantes : ET_EE.UTF-8,
LT_LT.UTF-8, LV_LV.UTF-8, ZH_CN.UTF-8.
- N'a pas mbstate_t.
- N'a pas mbrtowc.
Par conséquent je recommande l'utilisation des fonctions
redémarrables et multithread-safe wcsr/mbsr. Oubliez les systèmes qui
ne les ont pas (Irix, HP-UX, Aix), et utilisez le plug-in qui permet
d'utiliser des locales UTF-8, libutf8_plug.so (voir ci dessous) sur
les systèmes qui vous permettent de compiler des programmes qui
utilisent ces fonctions wcrs/mbsr (Linux, Solaris, OSF/1).
Un avis similaire, donné par Sun dans
http://www.sun.com/software/white-papers/wp-unicode/,
section "Internationalized Applications with Unicode", est :
Pour internationaliser correctement une application utilisez les
indications suivantes :
- Évitez l'accès direct à Unicode. Ceci est la tâche de la
couche d'internationalisation de la plateforme.
- Utilisez le modèles POSIX pour les interfaces multi-octets
et à caractères 16 bits.
- Appelez seulement les fonctions de l'API que la couche
d'internationalisation fournit pour la langue et les opération
spécifiques à la culture.
- Restez indépendant de l'encodage.
Si, pour une raison quelconque, vous devez vraiment supposer que
'wchar_t' est Unicode dans un morceau de code (par exemple, si vous
voulez faire un traitement spécial de certains caractères Unicode),
vous devriez rendre ce bout de code conditionnel selon le résultat de
is_locale_utf88() . Autrement vous allez mettre la pagaille
dans le comportement de votre programme sur d'autres plateformes, ou
si d'autres locales sont utilisées.
La fonction is_locale_utf8() est déclarée dans
utf8locale.h
et définie dans
utf8locale.c.
La bibliothèque libutf8
Une implémentation portable de l'API ISO/ANSI C, qui supporte les
locales 8-bits et les locales UTF-8, peut être trouvée dans
libutf8-0.5.2.tar.gz Avantages :
- Dès maintenant un support pour Unicode UTF-8 portable, même sur les
systèmes d'exploitation dont le support des caractères multi-octets ne
marche pas, ou qui n'ont pas du tout de support pour les caractères
multi-octets/larges.
- Le même binaire marche pour toutes les locales 8-bit et les locales
UTF-8 supportées par le système.
- Quand un système d'exploitation fournit un vrai support pour les
caractères multi-octets, vous pouvez en tirer avantage simplement en
recompilant sans l'option du compilateur -DHAVE_LIBUTF8.
La méthode Plan9
Le système d'exploitation Plan9, une variante d'Unix, utilise UTF-8
comme encodage dans toutes ses applications. Son type de caractère
large est appelé 'Rune ', pas 'wchar_ '. Des parties ce ses
bibliothèques, écrites par Rob Pike et Howard Trikey, sont
disponibles à
ftp://ftp.cdrom.com/pub/netlib/research/9libs/9libs-1.0.tar.gz.
Une autre bibliothèque similaire, écrite par Alistair G. Crook, est à
ftp://ftp.cdrom.com/pub/NetBSD/packages/distfiles/libutf-2.10.tar.gz.
En particulier, chacune de ces bibliothèques contient un moteur
d'expressions rationnelles qui comprend l'UTF-8.
Désavantages de cette API :
- UTF-8 est compilé dans la bibliothèque, pas optionnel. Les
programmes compilés dans cet univers perdent le
support des encodages 8-bits qui sont toujours utilisés fréquemment en
Europe.
Pour les interfaces utilisateur graphiques
La bibliothèque QT-2.0
http://www.troll.no/
contient la classe QString qui est totalement Unicode. Vous pouvez
utiliser les fonctions membres QString::utf8 et QString::fromUtf8 pour
convertir depuis/vers un texte encodé en UTF-8. Les fonctions
membres QString::ascii et QString::latin1 ne devraient plus être utilisées.
Pour la manipulation de texte avancée
Les bibliothèques mentionnées précédemment implémentent des versions
des concepts ASCII qui comprennent Unicode. Voici des bibliothèques
qui traitent des concepts Unicode, comme titlecase (Une troisième
casse de lettres, différente des majuscules et des minuscules), la
distinction entre la ponctuation et les symboles, la décomposition
canonique, les classes combinables, le classement canonique et
d'autres choses du même genre.
- ucdata-1.9
La bibliothèque ucdata de Mark Leisher
http://crl.nmsu.edu/~mleisher/ucdata.shtml
s'occupe des propriétés des caractères, de la conversion de la casse,
de la décomposition, des classes combinées.
- ICU
Ce sont les classes IBM pour Unicode.
http://www.alphaworks.ibm.com/tech/icu/.
Une bibliothèque très détaillée
comprenant des chaînes de caractères Unicode, des paquets de
ressources, des formateurs de nombres, de date, d'heure et de
messages, des assemblages, des assembleurs de messages et plus encore.
Beaucoup de locales sont supportées. Cette bibliothèque est portable
pour Unix et Win32, mais compilera sans intervention ("out of the
box") seulement avec la libc6, pas la libc5.
- libunicode
La librairie Unicode de GNOME
http://cvs.gnome.org/lxr/source/libunicode/
de Tom Tromey entre autres. Elle couvre la conversion du jeu de
caractères, les propriétés des caractères, la décomposition.
Pour la conversion
Deux bibliothèques de conversion qui supportent UTF-8 et un grand
nombre de de jeux de caractères 8-bits, sont disponibles :
L'implémentation iconv d'Ulrich Drepper, contenue dans la GNU glibc-2.2.1
ftp://ftp.gnu.org/pub/gnu/glibc/glibc-2.1.1.tar.gz.
Avantages :
- iconv est conforme au standard POSIX, les programmes qui l'utilisent
pour la conversion depuis/vers UTF-8 tourneront aussi sous
Solaris. Cependant le nom des jeux de caractères diffère entre les
plateformes. Par exemple, "EUC-JP" sous glibc devient "eucJP" sous
HP-UX. (Le nom INIA officiel pour ce jeu de caractères est
"EUC-JP". Il s'agit donc clairement d'une déficience de HP-UX.)
- Aucune bibliothèque supplémentaire n'est nécessaire.
librecode par François Pinard
ftp://ftp.gnu.org/pub/gnu/recode/recode-3.5.tar.gz.
Avantages :
- Support pour la translittération, i.e conversion de caractères non-ASCII
en séquences de caractères ASCII de façon à préserver la lisibilité
pour les humains, même lorsqu'une transformation sans pertes est
impossible.
Problèmes :
- Cette API est non standard.
Les autre approches
- libutf-8
libutf-8, de G.Adam.Stanislav
<adam@whizkidtech.net>
contient quelques fonctions pour la conversion depuis/vers des flux
"FILE*".
http://www.whizkidtech.net/i18n/libutf-8-1.0.tar.gz
Avantages :
Problèmes :
- API non standard ;
- UTF-8 est compilé dans la bibliothèque, pas optionnel. Les
programmes compilés dans cet univers perdent le
support des encodages 8-bits qui sont toujours utilisés fréquemment en
Europe ;
- L'installation n'est pas évidente : le Makefile doit être modifié. Pas d'auto-configuration.
5.2 Java
Java supporte Unicode en interne. Le type 'char' désigne un caractère
Unicode, et la classe 'java.lang.String' désigne une chaîne de
caractères construite à partir de caractères Unicode.
Java peut afficher n'importe quel caractère à travers son système de
fenêtrage AWT, à condition que
- vous positionniez la propriété système "user.language" de façon
appropriée.
- Les définitions de jeux de fontes
/usr/lib/java/lib/font.properties.language
soient appropriées, et
-
Le fontes spécifiées dans ce fichier soient installées.
Par exemple, pour afficher du texte contenant des caractères japonais,
vous devriez installer des fontes japonaise, et lancer "java
-Duser.language=ja ...". Vous pouvez combiner les jeux de fontes : pour
pouvoir afficher des caractères d'Europe de l'ouest, grecs et
japonais simultanément, vous devriez créer une combinaison des
fichiers "font.properties" (couvre ISO-8859-1), "font.properties.el"
(couvre ISO-8859-7) et "font.properties.ja" dans un seul fichier.
??Ceci n'a pas été testé??
Les interfaces java.io.DataInput et java.io.DataOutput contiennent des
méthodes appelées 'readUTF', et 'writeUTF' respectivement.
Mais notez qu'elles n'utilisent pas UTF-8 ; elles utilisent un encodage
UTF-8 modifié : le caractère NUL est encodé dans une séquence de deux
octets 0xC0 et 0x80 à la place de 0x00, et un octet 0x00 est ajouté à
la fin. Encodées de cette façon, les chaînes peuvent contenir des
caractères NUL mais elles doivent néanmoins être préfixées par un champ
de taille.
Les fonctions C <string.h> comme strlen() et strcpy() peuvent être
utilisées pour les manipuler.
5.3 Lisp
Le standard Lisp ordinaire détermine deux types de caractères :
'base-char' et 'character'. C'est à l 'implémentation d'ajouter un
support Unicode ou non. Ce langage détermine aussi un mot-clef
argument ':external-format' pour 'open' comme place naturelle pour
spécifier un jeu de caractères ou un encodage.
Parmi les implémentation gratuites du lisp standard, seul CLISP
http://clisp.cons.org/
supporte Unicode. Vous aurez besoin d'une version de CLISP datant de
juillet 99 ou plus récente.
ftp://clisp.cons.org/pub/lisp/clisp/source/clispsrc.tar.gz
Les types "base-char" et "character" sont tous équivalents au
16-bits Unicode. L'encodage utilisé pour le fichier ou l'I/O
socket/pipe peut être spécifié par l'argument ':external-format'.
Les encodages utilisés pour les opérations d'entrée/sortie sur des ttys
et l'encodage par défaut pour les I/O file/socket dépendent des
locales.
Parmi les implémentations commerciales du Lisp standard, seule Eclipse
http://www.elwood.com/eclipse/eclipse.htm
supporte Unicode. Voir
http://www.elwood.com/eclipse/char.htm
Le type 'base-char' est équivalent à ISO-8859-1, et le type
'character' contient tous les caractères Unicode.
L'encodage utilisé pour les entrées/sorties sur un fichier peut être
défini à travers une combinaison des arguments de 'open'
':element-type' et :'external.format'.
Limitations : les fonctions
d'attributs de caractères sont dépendantes des locales. Les sources
et les fichiers de sources compilés ne peuvent pas contenir des chaînes
Unicode littérales.
L'implémentation commerciale du Lisp standard Allegro CL ne contient
pas encore de support Unicode, mais Erik Naggum y travaille.
5.4 Ada95
Ada95 a été conçu pour supporter Unicode, et la bibliothèque standard
Ada95 contient les types de données spéciaux ISO 10646-1 Wide_Character et
Wide_String, ainsi que de nombreuses procédures et fonctions associées.
Le compilateur Ada95 GNU (gnat-3.11 ou plus) supporte UTF-8 comme
encodage externe des caractères 16 bits. Cela vous autorise à utiliser
UTF-8 à la fois dans le code source et dans les entrées/sorties de
l'application. Pour l'activer dans l'application, utilisez "WCEM=8"
dans la chaîne FORM quand vous ouvrez un fichier, et utilisez l'option
du compilateur "-gnatW8" si le code source est UTF-8. Pour plus de
détails, voyez les manuels de référence GNAT et Ada95.
[22 février 2002, JDNet]
|