OVH Cloud OVH Cloud

Support Unicode (UTF-8) et locales

24 réponses
Avatar
Vincent Lefevre
Il y a pas mal de doc sur Perl et Unicode, mais ça reste flou et le
comportement semble bizarre. Voici un exemple nommé "enctest":

#!/usr/bin/env perl
use strict;

my $agrave = chr(0xe0);
my $str = "A grave = '$agrave'";
print "stdout: $str\n";
print STDERR "stderr: $str\n";
warn " warn: $str\n";
die " die: $str\n";

Je voudrais obtenir un "à" encodé correctement, que ce soit avec des
locales en ISO-8859-1 ou avec des locales en UTF-8 (évidemment, le
terminal est configuré de manière cohérente avec les locales). Je me
demande ce que je dois ajouter à ce script (de manière la plus simple
possible).

Je passe sur le cas des locales en ISO-8859-1, qui ne posent pas
vraiment de problèmes. Je considère alors qu'on est en UTF-8.

Si j'exécute "./enctest" ou "perl enctest", ça sort en ISO-8859-1,
comme indiqué dans la doc. Je ne veux pas une solution basée sur
l'option -C, car je veux pouvoir exécuter le script comme ceci:
"./enctest". Il faut que la solution soit dans le script lui-même
(de manière aussi à ne pas affecter les autres scripts Perl, donc
pas de PERL_UNICODE non plus).

Cependant, l'option -C n'a pas l'air de bien fonctionner, donc je
vais tout de même mentionner ceci:

$ perl -C enctest
stdout: A grave = 'à'
stderr: A grave = 'à'
warn: A grave = '?'
die: A grave = '?'

Note: le '?' désigne ici un "à" encodé en ISO-8859-1, que le terminal
ne comprend donc pas. Pourquoi le warn et le die ne fonctionnent-ils
pas correctement?

Si j'utilise

use encoding ':locale';

alors j'obtiens sans l'option -C:

stdout: A grave = 'à'
stderr: A grave = '?'
warn: A grave = 'à'
die: A grave = 'à'

Un "man encoding" dit que STDERR n'est pas affecté par le use encoding,
c'est donc normal pour les deux premières lignes. Mais alors pourquoi
le warn et le die sont-ils maintenant en UTF-8???

Maintenant, si j'utilise seulement

use open OUT => ':locale';

alors j'ai le même résultat qu'avec -C (c'est cohérent). La solution
pour obtenir un "à" correctement encodé est d'utiliser les deux:

use encoding ':locale';
use open OUT => ':locale';

mais aucune idée du pourquoi...

Tout ceci est testé avec perl 5.8.7 sous Debian.

--
Vincent Lefèvre <vincent@vinc17.org> - Web: <http://www.vinc17.org/>
100% accessible validated (X)HTML - Blog: <http://www.vinc17.org/blog/>
Work: CR INRIA - computer arithmetic / SPACES project at LORIA

4 réponses

1 2 3
Avatar
FDA

substr $a, 6000, 2000



Tu plaisantes ? Cela se traduit certainement par moins de 5 instructions
assembleur ! C'est *long* , certes, mais en aucun cas *inefficace* .



Ce n'est jamais le nombre d'instructions qui est important,
mais le temps qu'on y passe.


Et tu penses vraiment que ce ne sera pas *largement* plus inefficace
avec un code de longueur variable qu'avec un code sur taille fixe ?

Avec un code de taille fixe, le substr, tu le fais en remplissant deux
champs d'un secripteur, sans aucun mouvement d'octets. Avec un code sur
taille fixe, tu ne peux *intrinsèquement* pas faire autrement que de
parcourir les caractères un par un en décrémntant un compteur jusqu'à ce
que tu aies le bon compte.

Ainsi donc, en reprenant très exactement ta définition, le substr - bien
programmé s'entend - sera plus efficace sur code à taille fixe. C'est un
point dont il n'y a me semble-t-il même pas à discuter.




Avatar
FDA

Une telle interface a d'autres intérêts que de gérer correctement les
caractères dont la représentation est de taille variable. En pariculier,
elle permet de gérer des chaînes dont la représentation n'est pas contiguë
en mémoire, ce qui autorise des opérations de concaténation rapide.


Mouais, je reconnais que ça et ce qui précède, c'est déjà plus
convaincant :-)


Bien sûr, de même que si l'on prend APL, on aura beaucoup plus
d'expression de tableaux et de rang



Quelque part, ça veut dire que l'interface des chaînes est plus puissante et
mieux conçue en Perl.


La grande erreur d'APL est de ne pas avoir autorisé très rapidement
l'indexation d'un tableau par une chaîne de caractères. Il n'y aurait
même pas eu besoin de caractères distincts {} et [] comme en Perl, la
nature de ce qui est entre crochet suffisant (et permettant même de
combiner numérique et chaînes : le pied intégral). En effet, je ne vois
pas beaucoup d'applications où l'on n'ait pas besoin à un moment ou à un
autre d'associer de l'information à une chaîne. C'est pour cela que je
suis passé d'APL à Perl.


Perl _a_ fait un choix sur
l'interface et la représentation des chaînes, choix qui me semble tout à
fait sain. À vrai dire, c'est le langage dont l'API des chaîne est la mieux
conçue parmi ceux que je connais.


Je reconnais que ce qui est géant, c'est d'écrire une maquette avec la
base de données en mémoire sous forme d'un hash, et ensuite de mapper ça
sur une vraie base sur disque. Je connais peu de langages qui aient
cette beauté et cette économie de moyens.


Avatar
Nicolas George
FDA wrote in message
<43af37f9$0$24312$:
Avec un code sur
taille fixe, tu ne peux *intrinsèquement* pas faire autrement que de
parcourir les caractères un par un en décrémntant un compteur jusqu'à ce
que tu aies le bon compte.


Sauf que (cf. l'autre branche du thread pour plus de détails), l'index en
caractères à partir duquel on veut prendre une sous-chaîne ne surgit pas
d'outre espace : il vient presque toujours d'un parcours de la chaîne, et
si l'API est bien conçue, il y a moyen de récupérer le compteur nécessaire
pour l'extraction à l'occasion : coût identique.

Avatar
Vincent Lefevre
Dans l'article <43af37f9$0$24312$,
FDA écrit:


substr $a, 6000, 2000



Tu plaisantes ? Cela se traduit certainement par moins de 5 instructions
assembleur ! C'est *long* , certes, mais en aucun cas *inefficace* .


Ce n'est jamais le nombre d'instructions qui est important,
mais le temps qu'on y passe.


Et tu penses vraiment que ce ne sera pas *largement* plus inefficace
avec un code de longueur variable qu'avec un code sur taille fixe ?


Le substr va faire une copie (la chaîne pouvant être modifiée plus
tard), ce qui est déjà assez inefficace. Ensuite libre à toi de
dire à Perl que c'est une chaîne d'octets si ça te suffit. Mais en
général, c'est plutôt que tu as choisie une mauvaise méthode pour
extraire une sous-chaîne.

Il faut voir aussi avec le reste du programme. Si tu perds O(n) dans
une étape alors que le programme complet est en Omega(n^2), ce n'est
pas forcément très grave.

--
Vincent Lefèvre - Web: <http://www.vinc17.org/>
100% accessible validated (X)HTML - Blog: <http://www.vinc17.org/blog/>
Work: CR INRIA - computer arithmetic / SPACES project at LORIA





1 2 3