perluniintro - Introduction à l'utilisation d'Unicode en Perl
Ce document donne une idée générale d'Unicode et de son utilisation en Perl.
Unicode est un jeu de caractères standardisé qui prévoit de codifier tous les systèmes d'écriture existant de par le monde ainsi que de nombreux autres symboles.
Unicode et ISO/IEC 10646 sont des normes qui attribuent un code pour les caractères de tous les jeux de caractères modernes, couvrant plus de 30 systèmes d'écriture et des centaines de langues, incluant toutes les langues modernes commercialement importantes. Tous les caractères chinois, japonais et cooréens en font aussi parti. Ces standards prévoient de couvrir tous les caractères de plus de 250 systèmes d'écriture et de milliers de langues. Unicode 1.0 est sorti en octobre 1991 et et sa version 4.0 en avril 2003.
Un caractère Unicode est une entité abstraite. Il n'est lié à
aucune taille d'entier en particulier et encore moins au type char
du language C. Unicode est neutre vis à vis de la langue et de
l'affichage : il ne code pas la langue utilisée par le texte et ne
définit pas de polices ou d'autres aspects de présentation
graphique. Unicode concerne les caractères et le texte composé de ces
caractères.
Unicode définit des caractères comme LATIN CAPITAL LETTER A
ou
GREEK SMALL LETTER ALPHA
et un nombre unique pour chacun de ces
caractères, en l'occurence respectivement 0x0041 et 0x03B1. Ces
nombres uniques sont appelés points de code ou plus simplement
numéros de caractères.
Le standard Unicode préfère la notation hexadécimale pour les numéros
de caractères. Si des nombres tels que 0x0041
ne vous sont pas
familiers, jetez un oeil à la section « Notation hexadécimale ». Le
standard Unicode utilise la notation U+0041 LATIN CAPITAL LETTER A
pour donner le numéro hexadécimal du caractère suivi de son nom
normalisé.
Unicode définit aussi différentes propriétés pour les caractères, telles que ``uppercase'' (majuscule) ou ``lowercase'' (minuscule), ``decimal digit'' (chiffre décimal) ou ``punctuation'' (ponctuation) ; ces propriétés étant indépendantes du nom des caractères. En outre, sont définies plusieurs opérations sur les caractères telles que ``passer en majuscule'', ``passer en minuscule'' et ``trier''.
Un caractère Unicode est constitué soit d'un unique caractère, soit
d'un caractère de base (tel que LATIN CAPITAL LETTER A
) suivi
d'un ou plusieurs modificateurs ou caractères combinatoires (tel
que COMBINING ACUTE ACCENT
). Cette séquence composée d'un
caractère de base suivi de ses modificateurs est appelée une
séquence combinante.
Le fait de considérer ces séquences comme étant un ``caractère'' dépend de votre point de vue. En tant que programmeur, vous aurez plutôt tendance à considérer chaque élément de la séquence pris séparément. Alors qu'un utilisateur considérera probablement la séquence complète comme étant un unique ``caractère'' car c'est de cette manière qu'il est perçu dans sa langue.
Avec la vision globale, déterminer le nombre total de caractères est difficile. Mais avec le point de vue du programmeur (chaque caractère, qu'il soit de base ou combinatoire, est un caractère), le concept de nombre de caractères est plus déterministe. Dans ce document, nous adopterons ce second point de vue : un ``caractère'' est un point de code Unicode, que ce soit un caractère de base ou un caractère combinatoire.
Pour certaines combinaisons, il existe des caractères précomposés.
Par exemple LATIN CAPITAL LETTER A WITH ACUTE
est défini comme un
point de code unique. Ces caractères précomposés ne sont disponibles
que pour certaines combinaisons et le sont principalement pour
faciliter la conversion entre Unicode et les anciens standards (tel
que ISO 8859). De manière générale, la méthode par combinaison est
plus extensible. Pour faciliter la conversion entre les différentes
manières de composer un caractère, plusieurs formes de
normalisation sont définies dans le but de standardiser les
représentations.
Pour des raisons de compatibilité avec les anciens systèmes de codage, l'idée ``un numéro unique pour chaque caractère'' est un peu remise en cause : en fait, il y a ``au moins un numéro pour chaque caractère''. Un même caractère peut être représenté différemment dans plusieurs anciens systèmes d'encodage. De même certains points de code ne correspondent à aucun caractère. En effet, d'une part, des blocs déjà utilisés contiennent des points de code non alloués. Et d'autre part, dans Unicode, on trouve des caractères de contrôle (ou de commande) et des caractères spéciaux qui ne représentent pas de vrais caractères.
Un mythe courant concernant Unicode est que celui-ci serait ``16
bits'' car il n'existe que 0x10000
(ou 65536) caractères entre
0x0000
et 0xFFFF
. Ceci est faux. Depuis Unicode 2.0 (juillet
1996), Unicode utilise 21 bits (0x10FFFF
) et depuis Unicode 3.1
(mars 2001), des caractères ont été définis au-delà de 0xFFFF
. Les
0x10000
premiers caractères sont appellés plan 0, ou encore
plan multilingue de base (PMP -- ou BMP en anglais). Avec Unicode
3.1, c'est 17 (oui, dix-sept) plans qui ont été définis mais ils ne
sont pas tous entièrement remplis, du moins pour le moment.
Un autre mythe est qu'il existerait une corrélation entre les langues
et les blocs de 256 caractères, chaque bloc définissant les caractères
utilisés par une langue ou un ensemble de langues. Ceci est tout
aussi faux. Cette division en bloc existe, mais elle est presque
totalement accidentelle, un simple artéfact de la manière dont les
caractères ont été et continuent à être alloués. En revanche, il
existe le concept d'écriture (ou script en anglais) qui est plus
utile : il existe une écriture latine
, une grecque
et ainsi
de suite. Les écritures sont généralement réparties sur plusieurs
blocs. Pour plus d'information consultez la page de manuel Unicode::UCD.
Les point de code Unicode ne sont que des nombres abstraits. Pour recevoir ou émettre ces nombres abstraits, ils faut les encoder ou les sérialiser d'une manière ou d'une autre. Unicode définit plusieurs formes d'encodage, parmi lesquelles UTF-8 est peut-être la plus populaire. UTF-8 est méthode d'encodage à taille variable qui encode les caractères Unicode sur 1 à 6 octets (maximum 4 pour les caractères actuellement définis). Les autres méthodes incluent UTF-16, UTF-32 et leur variantes grand-boutistes et petit-boutistes (UTF-8 est indépendant de l'ordre des octets). L'ISO/IEC définit aussi les formes UCS-2 et UCS-4.
Pour plus d'information à propos de l'encodage, par exemple pour savoir à quoi correspondent les caractères de substitution (surrogates) et les marques d'ordre d'octets (byte order marks ou BOMs), consultez perlunicode.
À partir de la version 5.6.0, Perl était apte à gérer Unicode nativement. Mais la version 5.8.0 a été la première version recommandée pour pouvoir travailler sérieusement avec Unicode. La version de maintenance 5.6.1 a corrigé un grand nombre des problèmes de l'implémentation initiale, mais par exemple, les expressions rationnelles ne fonctionnaient toujours pas en Unicode dans la version 5.6.1.
À partir de Perl 5.8.0, l'utilisation de use utf8
n'est plus
nécessaire. Dans les versions précédentes le pragma utf8
était
utilisé pour déclarer que les opérations du bloc ou du fichier courant
étaient compatibles Unicode. Ce modèle s'avéra mauvais, ou tout du
moins maladroit : la caractéristique ``Unicode'' est maintenant liée
aux données et non plus aux opérations. L'utilisation de use utf8
ne reste nécessaire que dans un seul cas : lorsque le script Perl
est lui-même encodé en UTF-8. Cele vous permet alors d'utiliser
l'UTF-8 pour vos identifiants ainsi que dans les chaînes de caractères
et les expressions rationnelles. Ceci n'est pas le règlage par défaut,
car sinon les scripts comportant des données encodées en 8 bits
risqueraient de ne plus fonctionner. Consultez utf8.
Perl supporte aussi bien les chaînes de caractères utilisant l'encodage pré-5.6 sur huit bits natifs que celles utilisant des caractères Unicode. Le principe est que Perl essaye au maximum de conserver les données avec l'encodage 8 bits, mais dès que Unicode devient indispensable, les données sont converties en Unicode de manière transparente.
En interne, Perl utilise le jeu de caractères natif sur 8 bit de la
plateforme (par exemple Latin-1) et pour encoder les chaines de
caractères Unicode, il utilise par défaut UTF-8. Plus précisement, si
tous les points de codes d'une chaîne sont inférieurs ou égal à
0xFF
, Perl utilisera l'encodage sur 8 bits natif. Sinon, il
utilisera UTF-8.
En général, l'utilisateur de Perl n'a besoin ni de savoir ni de se préoccuper de la manière dont Perl encode ses chaînes de caractères en interne, mais cela peut devenir utile lorsqu'on envoie des chaînes Unicode dans un flux n'utilisant pas PerlIO (il utilisera donc l'encodage par ``défaut''). Dans ce cas, les octets bruts utilisés en interne (reposant sur le jeu de caractères natif ou sur UTF-8, selon les chaînes) seront transmis et un avertissement ``Wide character'' sera émis pour les chaînes contenant un caractère dépassant 0x00FF.
Par exemple,
perl -e 'print "\x{DF}\n", "\x{0100}\x{DF}\n"'
produit un mélange plutôt inutile de caractères natifs et d'UTF-8 ainsi que l'avertissement :
Wide character in print at ...
Pour afficher de l'UTF-8, il faut utiliser la couche :utf8
. L'ajout
de :
binmode(STDOUT, ":utf8");
au début de ce programme d'exemple forcera l'affichage à être en totalité en UTF-8 et retirera les avertissements.
Vous pouvez automatiser l'utilisation de l'UTF-8 pour vos
entrées/sorties standard, pour les appels à open()
et pour @ARGV
en utilisant l'option -C
de la ligne de commande ou la variable
d'environnement PERL_UNICODE
. Consultez la page de manuel perlrun pour la
documentation de l'option -C
.
Notez que cela signifie que Perl espère que les autres logiciels fonctionnent eux-aussi en UTF-8 : si Perl est amené à croire que STDIN est en UTF-8 alors que STDIN provient d'une commande qui n'est pas en UTF-8, Perl se plaindra de caractères UTF-8 mal composés.
Toutes les fonctionnalités qui combinent Unicode et les E/S (I/O)
nécessitent l'usage de la nouvelle fonctionnalité PerlIO. La quasi
totalité des plateformes Perl 5.8 utilise PerlIO mais vous pouvez le
vérifier en lancant la commande ``perl -V'' et en recherchant
useperlio=define
.
Perl 5.8.0 supporte aussi Unicode sur les plateformes EBCDIC. Le support d'Unicode y est plus complexe à implémenter car il nécessite des conversions supplémentaires à chaque utilisation. Certains problèmes persistent ; consultez perlebcdic pour plus de détails.
Dans tous les cas, le support actuel d'Unicode sur les plateformes EBCDIC est bien meilleur que dans les versions 5.6 (cela ne fonctionnait quasiment pas sur les plateformes EBCDIC). Sur ces plateformes, l'encodage interne est UTF-EBCDIC au lieu d'UTF-8. La différence est que UTF-8 est ``ASCII-sûr'' dans le sens où les caractères ASCII sont codés tels quels en UTF-8, alors que UTF-EBCDIC est ``EBCDIC-sûr''.
Dans les littéraux, pour créer des caractères Unicode dont le point de
code est supérieur à 0xFF
, il faut utiliser la notation \x{...}
dans une chaîne entre guillemet :
my $smiley = "\x{263a}";
De la même façon, cette notation peut être utilisée dans les expressions rationnelles :
$smiley =~ /\x{263a}/;
À l'exécution vous pouvez utiliser chr()
:
my $hebrew_alef = chr(0x05d0);
Consultez « Autres ressources » pour savoir comment trouver ces codes numériques.
Évidemment, ord()
fera l'inverse : il transformera un caractère
en un point de code.
Notez que \x..
(sans {}
et avec seulement deux chiffres
hexadécimaux), \x{...}
ainsi que chr(...)
génèrent un caractère
sur un octet pour les arguments inférieurs à 0x100
(256 en décimal)
et ceci pour conserver une compatibilité ascendante avec les anciennes
versions de Perl. Pour les arguments supérieurs à 0xFF
, il s'agira
toujours de caractères Unicode. Si vous voulez forcer la génération
de caractères Unicode quelle que soit la valeur, utilisez
pack("U",...)
au lieu de \x..
, \x{...}
, ou chr()
.
Vous pouvez aussi utiliser le pragma charnames
pour invoquer les
caractères par leur nom entre guillemets :
use charnames ':full'; my $arabic_alef = "\N{ARABIC LETTER ALEF}";
Et, comme indiquer précédement, vous pouvez aussi utiliser la
fonction pack()
pour produire des caractères Unicode :
my $georgian_an = pack("U", 0x10a0);
Notez que \x{...}
et \N{...}
sont des constantes : vous ne
pouvez pas utiliser de variables dans ces notations. Si vous voulez un
équivalent dynamique, utilisez chr()
et charnames::vianame()
.
Si vous voulez forcer un résultat en caractères Unicode, utilisez le
préfixe spécial "U0"
. Il ne consomme pas d'argument mais force,
dans le résultat, l'utilisation de caractères Unicode à la place
d'octets.
my $chars = pack("U0C*", 0x80, 0x42);
De la même manière, vous pouvez forcer l'utilisation d'octets par le
préfixe spécial "C0"
.
La manipulation d'Unicode est quasi transparente : il suffit
d'utiliser les chaînes de caractères comme d'habitude. Les fonctions
comme index()
, length()
, et substr()
fonctionneront avec des
caractères Unicode et il en sera de même avec les expressions
rationnelles (consultez perlunicode et la page de manuel perlretut).
Notez que Perl considère les séquences combinantes comme étant composées de caractères séparés, par exemple :
use charnames ':full'; print length("\N{LATIN CAPITAL LETTER A}\N{COMBINING ACUTE ACCENT}"), "\n";
affichera 2 et non 1. La seule exception est l'utilisation de \X
dans les expressions rationnelles pour reconnaître une séquence
combinante de caractères.
En revanche, les choses ne sont malheureusement pas toujours aussi transparentes que ce soit avec l'encodage natif, avec les E/S ou dans certaines situations spéciales. C'est que nous allons détaillé maintenant.
Lorsque vous utilisez conjointement des données natives et des données
Unicode, les donnés natives doivent être converties en Unicode. Par
défaut ISO 8859-1 (ou EBCDIC selon le cas) est utilisé. Vous pouvez
modifier ce comportement en utilisant le pragma encoding
, par
exemple :
use encoding 'latin2'; # ISO 8859-2
Dans ce cas, les littéraux (chaînes et expressions rationnelles),
chr()
et ord()
produiront de l'Unicode en supposant un codage
initiale en ISO 8859-2. Notez que le nom de l'encodage est reconnu de
manière indulgente : au lieu de latin2
on aurait pu utiliser
Latin2
, ou iso8859-2
ou encore d'autres variantes. En utilisant
seulement :
use encoding;
la valeur de la variable PERL_ENCODING
sera alors utilisée. Si
cette variable n'est pas positionnée, le pragma échouera.
Le module Encode
connait de nombreux encodages et fournit une
interface pour faire des conversions entre eux :
use Encode 'decode'; $data = decode("iso-8859-3", $data); # convertit du natif vers utf-8
Normalement, l'affichage de données Unicode
print FH $une_chaine_avec_unicode, "\n";
produit les octets bruts utilisés en interne par Perl pour encoder la
chaîne Unicode. Le système d'encodage interne dépend du systèmes ainsi
que des caractères présents dans la chaîne. S'il y a au moins un
caractère ayant un code suppérieur ou égal à 0x100
, vous obtiendrez
un avertissement. Pour être sûr que la sortie utilise explicitement
l'encodage que vous désirez, et pour éviter l'avertissement, ouvrez le
flux avec l'encodage désiré. Quelques exemples :
open FH, ">:utf8", "fichier";
open FH, ">:encoding(ucs2)", "fichier"; open FH, ">:encoding(UTF-8)", "fichier"; open FH, ">:encoding(shift_jis)", "fichier";
et sur les flux déjà ouverts, utilisez binmode()
:
binmode(STDOUT, ":utf8");
binmode(STDOUT, ":encoding(ucs2)"); binmode(STDOUT, ":encoding(UTF-8)"); binmode(STDOUT, ":encoding(shift_jis)");
Les noms d'encodages sont peu regardants : la casse n'a pas
d'importance et beaucoup possèdent plusieurs alias. Notez par contre
que le filtre :utf8
doit toujours être spécifiée exactement de
cette manière ; il n'est pas reconnue de manière aussi
permissive que les noms d'encodages.
Consultez PerlIO pour en savoir plus sur le filtre :utf8
,
la page de manuel PerlIO::encoding et la page de manuel Encode::PerlIO pour tout ce qui concerne le
filtre :encoding()
et la page de manuel Encode::Supported pour les nombreux
encodages reconnus par le module Encode
.
La lecture d'un fichier que vous savez être encodés en Unicode ou en natif ne convertira pas magiquement les données en Unicode aux yeux de Perl. Pour cela, spécifier la couche désirée à l'ouverture du fichier :
open(my $fh,'<:utf8', 'anything'); my $ligne_unicode = <$fh>;
open(my $fh,'<:encoding(Big5)', 'anything'); my $ligne_unicode = <$fh>;
Pour plus de flexibilité, le filtre E/S peut aussi être spécifié via
le pragma open
. Consultez open ou l'exemple suivant :
use open ':utf8'; # les entrees et sorties seront par defaut en UTF-8 open X, ">file"; print X chr(0x100), "\n"; close X; open Y, "<file"; printf "%#x\n", ord(<Y>); # Cela devrait afficher 0x100 close Y;
Avec le pragma open
vous pouvez utiliser le filtre :locale
:
BEGIN { $ENV{LC_ALL} = $ENV{LANG} = 'ru_RU.KOI8-R' } # :locale va utiliser les variables d'environnements des locales comme LC_ALL use open OUT => ':locale'; # russki parusski open(O, ">koi8"); print O chr(0x430); # Unicode CYRILLIC SMALL LETTER A = KOI8-R 0xc1 close O; open(I, "<koi8"); printf "%#x\n", ord(<I>), "\n"; # ceci devrais afficher 0xc1 close I;
ou vous pouvez aussi utiliser le filtre ':encoding(...)'
:
open(my $epic,'<:encoding(iso-8859-7)','iliad.greek'); my $ligne_unicode = <$epic>;
Ces méthodes installent, sur le flux d'entrée/sortie, un filtre transparent qui, lors de leur lecture à partir du flux, convertit les données depuis l'encodage spécifié. Le résultat est toujours de l'Unicode.
En instaurant un filtre par défaut, le pragma open impacte tous les
appels à open()
qui suivront. Si vous ne voulez modifier que
certains flux, utilisez les filtres explicites directement dans les
appels à open()
.
Vous pouvez modifier l'encodage d'un flux déjà ouvert en utilisant
binmode()
; consultez binmode dans la page de manuel perlfunc.
Le filtre :locale
ne peut pas, à l'heure actuelle (comme dans Perl
5.8.0), fonctionner avec open()
et binmode()
mais seulement avec
le pragma open
. Par contre :utf8
et :encoding(...)
fonctinnent avec open()
, binmode()
et le pragma open
.
De la même manière, vous pouvez utiliser les filtres d'E/S sur un flux en sortie pour convertir automatiquement depuis Unicode vers l'encodage spécifié, lors des écritures dans ce flux. Par exemple, le code suivant copie le contenu du fichier ``text.jis'' (encodé en ISO-2022-JP, autrement dit JIS) dans le fichier ``text.utf8'', encodé en UTF-8 :
open(my $nihongo, '<:encoding(iso-2022-jp)', 'text.jis'); open(my $unicode, '>:utf8', 'text.utf8'); while (<$nihongo>) { print $unicode $_ }
Les noms des encodages fournis à open()
ou au pragma open
, sont
similaires à ceux du pragma encoding
en ce qui concerne la
flexibilité : koi8-r
et KOI8R
seront interprétés de la même
manière.
Les encodages communément reconnus par l'ISO, en MIME ou par l'IANA et divers organismes de normalisation sont aussi Sreconnus ;> pour une liste plus détaillée consultez la page de manuel Encode::Supported.
La fonction read()
lit des caractères et renvoie le nombre de
caractère lus. Les fonctions seek()
et tell()
utilisent un
nombre d'octets ainsi que sysread()
et sysseek()
.
Notez qu'à cause du comportement par défaut qui consiste à ne pas faire de conversion si aucun filtre par défaut n'est défini, il est facile d'écrire du code qui fera grossir un fichier en ré-encodant les données déjà encodées :
# ATTENTION CODE DEFECTUEUX open F, "file"; local $/; ## lis l'ensemble du fichier sous forme de caractères 8 bits $t = <F>; close F; open F, ">:utf8", "file"; print F $t; ## conversion en UTF-8 sur la sortie close F;
Si vous exécutez deux fois ce code, le contenu de file sera
doublement encodé en UTF-8. L'utilisation de use open ':utf8'
aurait permis d'éviter ce bug ou on aurait pu aussi ouvrir file
explicitement en UTF-8.
NOTE: Les fonctionnalités :utf8
et :encoding
ne fonctionnent
que si votre Perl a été compilé avec la nouvelle fonctionnalité PerlIO
(ce qui est le cas par défaut sur la plupart des systèmes).
Il peut arriver que vous vouliez afficher des scalaires Perl contenant
de l'Unicode comme un simple texte ASCII (ou EBCDIC). La sous-routine
suivante convertit ses arguments de telle manière que les caractères
Unicode dont le point de code est supérieur à 255 sont affichés sous
la forme \x{...}
, que les caractères de contrôle (comme \n
) sont
affichés sous la forme \x..
et que le reste est affiché sans
conversion :
sub nice_string { join("", map { $_ > 255 ? # Si caractère étendu ... sprintf("\\x{%04X}", $_) : # \x{...} chr($_) =~ /[[:cntrl:]]/ ? # Si caractère de contrôle ... sprintf("\\x%02X", $_) : # \x.. quotemeta(chr($_)) # Sinon sous forme quoted } unpack("U*", $_[0])); # Extrait les caractères Unicode }
Par exemple,
nice_string("foo\x{100}bar\n")
renvoie la chaîne :
'foo\x{0100}bar\x0A'
qui est prête à être imprimée.
vec()
L'opérateur de complément bit à bit ~
peut produire des résultats
surprenants s'il est utilisé sur une chaîne contenant des caractères
dont le point de code est supérieur à 255. Dans un tel cas, le
résultat sera conforme à l'encodage interne, mais pas avec grand chose
d'autre. Alors, ne le faites pas. Le même problème se pose avec la
fonction vec()
: elle agit sur le motif de bits utilisé en
interne pour stocker les caractères Unicode et non sur la valeur du
point de code, ce qui n'est probablement pas ce que vous souhaitez.
Les utilisateurs normaux de Perl ne devraient jamais se préoccuper de la manière dont celui-ci encode les chaînes Unicode (parce que la bonne manière de récupérer le contenu d'une chaîne Unicode, en entrée et en sortie, devrait toujours être via un filtre d'E/S explicitement indiqué). Mais si besoin est, voici deux manières de regarder derrière le rideau.
Une première manière d'observer l'encodage interne des caractères
Unicode est d'utiliser unpack("C*", ...
pour récupérer les octets
ou unpack("H*", ...)
pour les afficher :
# Affiche c4 80 pour le code UTF-8 0xc4 0x80 print join(" ", unpack("H*", pack("U", 0x100))), "\n";
Une autre manière de faire est d'utiliser le module Devel::Peek :
perl -MDevel::Peek -e 'Dump(chr(0x100))'
qui affiche, dans FLAGS, le drapeau UTF8
et, dans PV
, les deux
octets UTF-8 ainsi que le caractère Unicode. Consultez aussi la
section concernant la fonction utf8::is_utf8()
plus loin dans ce
document.
La question de l'équivalence ou de l'égalité de deux chaînes se complique singulièrement avec Unicode : que voulez-vous dire par ``égale'' ?
(LATIN CAPITAL LETTER A WITH ACUTE
est-il égal à LATIN CAPITAL
LETTER A
?)
La réponse courte est que par défaut pour les équivalence (eq
,
ne
) Perl ne se base que sur les points de codes des
caractères. Donc, dans le cas ci-dessus, la réponse est non (car
0x00C1 != 0x0041). Mais quelque fois, toutes les CAPITAL LETTER
devrait être considérés comme égale, ou même tous les A.
Pour une réponse détaillée, il faut considérer la normalisation et les problèmes de casse : consultez la page de manuel Unicode::Normalize, Unicode Technical Reports #15 and #21, Unicode Normalization Forms et Case Mappings, http://www.unicode.org/unicode/reports/tr15/ et http://www.unicode.org/unicode/reports/tr21/ .
Depuis la version 5.8.0. de Perl, le cas ``Full'' case-folding de Case Mappings/SpecialCasing est implémenté.
Le gens aiment que leurs chaînes de caractères soient correctement triées, le terme anglais utilisé pour Unicode est ``collated''. Mais, que veux dire trier ?
(Doit-on placé LATIN CAPITAL LETTER A WITH ACUTE
avont ou après
LATIN CAPITAL LETTER A WITH GRAVE
?)
La réponse courte est que par défaut, les opérateurs de comparaison de
chaîne (lt
, le
, cmp
, ge
, gt
) de Perl ne se basent que
sur le point de code des caractères. Dans le cas précédent, la réponse
est ``après'', car 0x00C1
> 0x00C0
.
La réponse détaillée est ``ça dépend'', et une bonne réponse ne peut être donnée sans connaître (au moins) le contexte linguistique. Consultez la page de manuel Unicode::Collate, et Unicode Collation Algorithm http://www.unicode.org/unicode/reports/tr10/
Les plages de caractères dans les classes des expressions rationnelles
(/[a-z]/
) et dans l'opérateur tr///
(aussi connu sous le nom
y///
) ne sont pas magiquement adaptées à Unicode. Cela signifie que
[A-Za-z]
ne correspondra pas automagiquement à ``toutes les lettres
alphabétiques'' ; ce n'est déjà pas le cas pour les caractères 8
bits, et vous devrez utiliser /[[:alpha:]]/
dans ce cas.
Pour spécifier un classe de caractères comme celle-ci dans les
expressions rationnelles, vous pouvez utiliser plusieurs propriétés
Unicode (\pL
, ou éventuellement \p{Alphabetic}
, dans ce cas
particulier). Vous pouvez aussi utiliser un point de code Unicode
comme borne de plage, mais il n'y aucune magie associée à la
spécification de ces plages. Pour plus d'informations, il existe des
douzaines de classes de caractères Unicode, consultez perlunicode.
Unicode définit plusieurs caractères séparateurs décimal et plusieurs caractères numériques, en dehors des chiffres habituels 0 à 9, tels que les chiffres Arabes et Indien. Perl ne supporte pas la conversion des chaînes vers des nombres pour les chiffres autres que 0 à 9 ASCII (et a à f ASCII pour l'hexadécimal).
Très probablement. À moins que vous ne génériez déjà des caractères
Unicode vous-même, l'ancien comportement devrait être conservé. Le
seul comportement qui change et qui pourrait générer de l'Unicode
accidentellement est celui de chr()
lorsqu'on lui fourni un
argument supérieur à 255 : auparavant, il renvoyait le caractère
correspondant à son argument modulo 255. Par exemple, chr(300)
était égal à chr(45)
ou ``-'' (en ASCII) alors que maintenant il
produit LATIN CAPITAL LETTER I WITH BREVE.
Très peu de choses doivent être faites sauf si vous génériez déjà des données Unicode. La plus importante est d'obtenir un flux d'entrée en Unicode ; reportez vous à la section ci-dessus concernant les entrées/sorties.
Vous ne devriez pas vous en préoccuper. Non, vous ne devriez vraiment pas. Non, vraiment. Si vous le devez absolument, à part dans les cas décrits précédement, ça signifie que vous n'avez pas enocre atteint la transparence d'Unicode.
Bon, puisque vous insistez :
print utf8::is_utf8($string) ? 1 : 0, "\n";
Mais notez bien que cela ne signifie pas qu'un caractère de la chaîne
est forcément encodé en UTF-8, ou qu'un caractère a un point de code
supérieur à 0xFF (255) ou même à 0x80 (128), ou que la chaîne contient
au moins un caractère. La seule chose que is_utf8()
fait, c'est
retourner la valeur du drapeau interne ``utf8ness'' attaché à
$string
. Si ce drapeau n'est pas positionné, les octets du scalaire
sont interprétés comme étant encodés sur un octet. S'il est
positionné, les octets du scalaires sont interprétés comme les points
de code (multi-octets, de taille variable) UTF-8 des caractères. Les
octets ajoutés à une chaîne encodées en UTF-8 sont automatiquement
convertis en UTF-8. Si un scalaire non-UTF-8 est combiné à un scalaire
UTF-8 (par interpolation dans des guillemets, par concaténation
explicite ou par substitution des paramètres de printf/sprintf), le
résultat sera une chaîne encodée en UTF-8. Par exemple :
$a = "ab\x80c"; $b = "\x{100}"; print "$a = $b\n";
La chaîne affichée sera ab\x80c = \x{100}\n
encodée en UTF-8, mais
$a
restera encodé en simple octet.
Il vous faudra quelque fois connaître la taille en octets d'une chaîne
et non en caractères. Pour ceci utilisez la fonction
Encode::encode_utf8()
ou encore le pragma bytes
et length()
,
la seule fonction qu'il définit :
my $unicode = chr(0x100); print length($unicode), "\n"; # Affiche 1 require Encode; print length(Encode::encode_utf8($unicode)), "\n"; # Affiche 2 use bytes; print length($unicode), "\n"; # Affiche 2 # (les codes 0xC4 0x80 de l'UTF-8)
Utilisez le package Encode
pour tenter de les convertir. Par
exemple :
use Encode 'decode_utf8'; if (decode_utf8($suite_octets_qu_on_pense_etre_utf8)) { # valide } else { # invalide }
Si il n'y a que UTF-8 qui vous intéresse, vous pouvez utiliser :
use warnings; @chars = unpack("U0U*", $suite_octets_quon_pense_etre_utf8);
Si c'est invalide, un avertissement Malformed UTF-8 character (byte
0x##) in unpack
est produit. ``U0'' signifie ``n'attends strictement que
de l'UTF-8''. Sans ça, unpack("U*",...)
accepterait des données
telle que chr(0xFF)
, comme pack
ainsi que nous l'avons vu
précédemment.
Ce n'est probablement pas aussi utile que vous pourriez le penser. Normalement, vous ne devriez pas en avoir besoin.
Dans un sens, ce que vous demandez n'a pas beaucoup de sens : l'encodage concerne les caractères et des données binaires ne sont pas des ``caractères'', donc la conversion de ``données'' dans un encodage n'a pas sens à moins de connaître le jeu de caractères et l'encodage utilisés par ces données, mais dans ce cas il ne s'agit plus de données binaires.
Si vous disposez d'une séquence brute d'octets pour laquelle vous
connaissez l'encodage particulier à utiliser, vous pouvez utiliser
Encode
:
use Encode 'from_to'; from_to($data, "iso-8859-1", "utf-8"); # de latin-1 à utf-8
L'appel à from_to()
change les octets dans $data
, mais la nature
de la chaîne du point de vue de Perl n'est pas modifiée. Avant et
après l'appel, la chaîne $data
est juste un ensemble d'octets 8
bits. Pour Perl, l'encodage de cette chaîne reste ``octets 8 bits
natifs du système''.
Vous pourriez mettre ceci en relation avec un hypothétique module 'Translate' :
use Translate; my $phrase = "Yes"; Translate::from_to($phrase, 'english', 'deutsch'); ## phrase contient maintenant "Ja"
Le contenu de la chaîne change, mais pas la nature de la chaîne. Perl n'en sais pas plus après qu'avant sur la nature affirmative ou non de la chaîne.
Revenons à la conversion de données. Si vous avez (ou voulez) des données utilisant l'encodage 8 bits natif de votre système (c-à-d. Latin-1, EBCDIC, etc.), vous pouvez utiliser pack/unpack pour convertir vers/depuis Unicode.
$native_string = pack("C*", unpack("U*", $Unicode_string)); $Unicode_string = pack("U*", unpack("C*", $native_string));
Si vous avez une séquence d'octets que vous savez être de l'UTF-8 valide, mais que Perl ne le sait pas encore, vous pouvez le convaincre via :
use Encode 'decode_utf8'; $Unicode = decode_utf8($bytes);
Vous pouvez convertir de l'UTF-8 bien formé en une séquence d'octets,
mais si vous voulez convertir des données binaires aléatoires en de
l'UTF-8, c'est impossible. Toutes les séquences d'octets ne forment
par une chaîne UTF-8 bien formée. Vous pouvez utiliser unpack("C*",
$string)
pour la première opération et vous pouvez créer une chaîne
Unicode bien formée avec pack("U*", 0xff, ...)
.
Consultez http://www.alanwood.net/unicode/ et http://www.cl.cam.ac.uk/~mgk25/unicode.html .
En Perl, ça ne marche pas très bien. Evitez d'utiliser les locales
avec le pragma locale
. Utilisez soit l'un soit l'autre. Mais voyez
la page de manuel perlrun pour la description de l'argument -C
et la variable
d'environnement équivalente $ENV{PERL_UNICODE}
pour savoir comment
activer les différentes fonctionnalités Unicode, par exemple en
utilisant le paramétrage des locales.
Le standard Unicode privilégie la notation hexadécimale car cela
montre plus clairement la division d'Unicode en blocs de 256
caractères. L'hexadécimal est aussi plus court que le décimal. Vous
pouvez toujours utiliser la notation décimale, bien sûr, mais
l'apprentissage de l'hexadécimal vous facilitera la vie avec le
standard Unicode. La notation U+HHHH
utilise l'hexadécimal, par
exemple.
Le préfixe 0x
indique un nombre hexadécimal, les chiffres étant
0
à 9
et a
à f
(ou A
à F
, la casse n'ayant pas
d'importance). Chaque chiffre hexadécimal représente quatres bits,
autrement dit la moitié d'un octet. print 0x..., "\n"
affiche un
nombre hexadécimal convertit en décimal et printf "%x\n", $decimal
affiche un nombre décimal convertit en hexadécimal. Si vous n'avez que
les ``chiffres'' d'un nombre hexadécimal, vous pouvez aussi utiliser la
fonction hex()
.
print 0x0009, "\n"; # 9 print 0x000a, "\n"; # 10 print 0x000f, "\n"; # 15 print 0x0010, "\n"; # 16 print 0x0011, "\n"; # 17 print 0x0100, "\n"; # 256
print 0x0041, "\n"; # 65
printf "%x\n", 65; # 41 printf "%#x\n", 65; # 0x41
print hex("41"), "\n"; # 65
http://www.unicode.org/
http://www.unicode.org/unicode/faq/
http://www.unicode.org/glossary/
http://www.unicode.org/unicode/onlinedat/resources.html
http://www.alanwood.net/unicode/
http://www.cl.cam.ac.uk/~mgk25/unicode.html
http://www.czyborra.com/ http://www.eki.ee/letter/
$Config{installprivlib}/unicore
en Perl 5.8.0 ou plus récent, et dans
$Config{installprivlib}/unicode
dans les versions 5.6.x. (Le renommage en lib/unicore a été décidé
pour éviter les conflits avec lib/Unicode sur les systèmes de fichiers
insensible à la casse). Le fichier principale des données Unicode est
UnicodeData.txt (or Unicode.301 en Perl 5.6.1.) Vous pouvez
obtenir la valeur de $Config{installprivlib}
via
perl "-V:installprivlib"
Vous pouvez explorer les informations des fichiers de données Unicode
en utilisant le module Unicode::UCD
.
Si vous ne pouvez pas mettre à jour votre Perl en version 5.8.0 ou
plus récente, vous pouvez toujours traiter de l'Unicode en utilisant
les modules Unicode::String
, Unicode::Map8
, et Unicode::Map
,
disponibles sur le CPAN. Si vous avez installé GNU recode, vous
pouvez aussi utiliser le front-end Perl Convert::Recode
pour les
conversions de caractères.
Les exemples suivants proposent une conversion rapide d'octets ISO 8859-1 (Latin-1) en octets UTF-8 et inversement, ce code fonctionnant aussi avec les versions plus anciennes de Perl 5.
# ISO 8859-1 vers UTF-8 s/([\x80-\xFF])/chr(0xC0|ord($1)>>6).chr(0x80|ord($1)&0x3F)/eg;
# UTF-8 vers ISO 8859-1 s/([\xC2\xC3])([\x80-\xBF])/chr(ord($1)<<6&0xC0|ord($2)&0x3F)/eg;
perlunicode, Encode, encoding, open, utf8, bytes, la page de manuel perlretut, la page de manuel perlrun, la page de manuel Unicode::Collate, la page de manuel Unicode::Normalize et la page de manuel Unicode::UCD.
Merci aux lecteurs des listes de diffusion perl5-porters@perl.org, perl-unicode@perl.org, linux-utf8@nl.linux.org et unicore@unicode.org pour leurs commentaires précieux.
Copyright 2001-2002 Jarkko Hietaniemi <jhi@iki.fi>
Ce document peut être distribué sous les mêmes conditions que Perl lui-même.
Cette traduction française correspond à la version anglaise distribuée avec perl 5.8.8. Pour en savoir plus concernant ces traductions, consultez http://perl.enstimac.fr/.
Marc Carmier <mcarmier@gmail.com>.
Paul Gaborit (Paul.Gaborit arobase enstimac.fr).