Utilisation de 'use utf8;' me donne un 'caractère large dans l'impression'

86

Si j'exécute le programme Perl suivant:

perl -e 'use utf8; print "鸡\n";'

Je reçois cet avertissement:

Wide character in print at -e line 1.

Si j'exécute ce programme Perl:

perl -e 'print "鸡\n";'

Je ne reçois pas d'avertissement.

Je pensais qu'il use utf8était nécessaire d'utiliser des caractères UTF-8 dans un script Perl. Pourquoi cela ne fonctionne-t-il pas et comment puis-je y remédier? J'utilise Perl 5.16.2. J'ai le même problème si cela se trouve dans un fichier au lieu d'être une seule ligne sur la ligne de commande.

Eric Johnson
la source
3
"Pourquoi ça ne marche pas?" Il fait le travail, mais il a été mon expérience avec Unicode , il y a beaucoup de programmes très cassé là - bas que regarder comme ils travaillent. Lorsque vous corrigez une chose, rendant le code un peu moins faux, les résultats semblent bien pires. Ce n'est que lorsque vous réparez la dernière partie que tout semble bon à nouveau.
hobbs

Réponses:

110

Sans use utf8Perl interprète votre chaîne comme une séquence de caractères à un octet. Il y a quatre octets dans votre chaîne comme vous pouvez le voir:

$ perl -E 'say join ":", map { ord } split //, "鸡\n";'
233:184:161:10

Les trois premiers octets composent votre caractère, le dernier est le saut de ligne.

L'appel à printenvoie ces quatre caractères à STDOUT. Votre console détermine ensuite comment afficher ces caractères. Si votre console est configurée pour utiliser UTF8, elle interprétera ces trois octets comme votre caractère unique et c'est ce qui s'affiche.

Si nous ajoutons dans le utf8module, les choses sont différentes. Dans ce cas, Perl interprète votre chaîne comme seulement deux caractères.

$ perl -Mutf8 -E 'say join ":", map { ord } split //, "鸡\n";'
40481:10

Par défaut, la couche IO de Perl suppose qu'elle fonctionne avec des caractères à un octet. Ainsi, lorsque vous essayez d'imprimer un caractère multi-octets, Perl pense que quelque chose ne va pas et vous avertit. Comme toujours, vous pouvez obtenir plus d'explications sur cette erreur en incluant use diagnostics. Il dira ceci:

(S utf8) Perl rencontrait un caractère large (> 255) alors qu'il n'en attendait pas. Cet avertissement est activé par défaut pour les E / S (comme l'impression). Le moyen le plus simple de calmer cet avertissement est simplement d'ajouter la couche: utf8 à la sortie, par exemple binmode STDOUT, ': utf8'. Une autre façon de désactiver l'avertissement est de n'ajouter aucun avertissement «utf8»; mais c'est souvent plus proche de la triche. En général, vous êtes censé marquer explicitement le descripteur de fichier avec un encodage, voir open et perlfunc / binmode.

Comme d'autres l'ont souligné, vous devez dire à Perl d'accepter la sortie multi-octets. Il existe de nombreuses façons de procéder (voir le didacticiel Perl Unicode pour quelques exemples). L'un des moyens les plus simples est d'utiliser l' -CSindicateur de ligne de commande - qui indique aux trois descripteurs de fichier standard (STDIN, STDOUT et STDERR) de gérer UTF8.

$ perl -Mutf8 -e 'print "鸡\n";'
Wide character in print at -e line 1.
鸡

contre

$ perl -Mutf8 -CS -e 'print "鸡\n";'

Unicode est un domaine vaste et complexe. Comme vous l'avez vu, de nombreux programmes simples semblent faire la bonne chose, mais pour les mauvaises raisons. Lorsque vous commencez à réparer une partie du programme, les choses empirent souvent jusqu'à ce que vous ayez réparé tout le programme.

Dave Cross
la source
Comment épeler -Mutf8sinon en un seul liner perl?
Lei Yang
@LeiYang:use utf8;
Dave Cross
80

Il use utf8;suffit de dire à Perl que le code source est encodé en UTF-8. Vous devez indiquer à Perl comment encoder votre texte:

use open ':std', ':encoding(UTF-8)';
ikegami
la source
Merci, cela fonctionne bien pour les programmes stockés dans des fichiers, par opposition aux one-liners sur la ligne de commande, ce que couvre la réponse de @ DaveCross.
vktec
19

Encodez toutes les sorties standard en UTF-8:

binmode STDOUT, ":utf8";
Boris Ivanov
la source
2
use open ':std', ':encoding(UTF-8)';comme proposé par une autre réponse, cela fait cela pour STDOUT mais marque également STDERR et STDIN comme UTF-8, vous en obtenez donc trois pour le prix d'une instruction. Voir aussi stackoverflow.com/a/42194059
Stephen Ostermiller le
Se mettre d'accord. C'est encore mieux.
Boris Ivanov le
14

Vous pouvez vous rapprocher de "juste faire utf8 partout" en utilisant le module CPAN utf8::all.

perl -Mutf8::all -e 'print "鸡\n";'

Lorsqu'il printreçoit quelque chose qu'il ne peut pas imprimer (caractère plus grand que 255 quand aucune :encodingcouche n'est fournie), il suppose que vous vouliez l'encoder en UTF-8. Il le fait, après avoir averti du problème.

Joël Berger
la source
5

Vous pouvez utiliser ceci,

perl -CS filename.

Cela mettra également fin à cette erreur.

Karthikeyan.RS
la source
seulement cela a aidé
muenalan
0

En espagnol, vous pouvez trouver cette erreur à côté de commencer à utiliser:

use utf8;

L'encodage de votre éditeur est dans un encodage différent. Donc, ce que vous voyez sur l'éditeur n'est pas ce que fait Perl. Pour résoudre cette erreur, changez simplement l'encodage de l'éditeur en Unicode / UTF-8 .

DiegoAr
la source
1
Non, ce n'est pas ce qui a causé l'erreur. Le code était correctement codé en UTF8 mais le descripteur de fichier de sortie ne savait pas que c'était le cas.
Dave Cross