Comment puis-je sortir UTF-8 depuis Perl?

110

J'essaye d'écrire un script Perl en utilisant le pragma "utf8" et j'obtiens des résultats inattendus. J'utilise Mac OS X 10.5 (Leopard) et j'édite avec TextMate. Tous mes paramètres pour mon éditeur et mon système d'exploitation sont définis par défaut sur l'écriture de fichiers au format utf-8.

Cependant, lorsque j'entre ce qui suit dans un fichier texte, que je l'enregistre en tant que ".pl" et que je l'exécute, j'obtiens le sympathique "diamant avec un point d'interrogation" à la place des caractères non ASCII.

#!/usr/bin/env perl -w

use strict;
use utf8;

my $str = 'Çirçös';
print( "$str\n" );

Une idée de ce que je fais mal? Je m'attends à avoir 'Çirçös' dans la sortie, mais j'obtiens à la place ' ir s'.

dda
la source
1
Peut-être que ce n'est pas le programme .. je pense que c'est votre shell ou votre éditeur qui fait la sortie
n00ki3
Toutes les réponses répondent correctement à votre question sur la manière de le définir explicitement sur UTF8. Je pense que vous devriez vous adapter aux paramètres régionaux de votre terminal, comme indiqué dans stackoverflow.com/a/14405949/498634 . Le terminal n'est peut-être pas réglé sur UTF8 et les données écrites sur STDOUT en UTF8 seront codées de manière incorrecte !
Daniel Böhmer
Excellente réponse comment travailler avec utf8:
Eugen Konkov le

Réponses:

160

use utf8;n'active pas la sortie Unicode - il vous permet de taper Unicode dans votre programme. Ajoutez ceci au programme, avant votre print()déclaration:

binmode(STDOUT, ":utf8");

Voyez si cela aide. Cela devrait produire une STDOUTsortie en UTF-8 au lieu de l'ASCII ordinaire.

Chris Lutz
la source
Je ne savais pas à ce sujet (j'ai seulement mis UTF8 dans une base de données, je ne l'ai jamais imprimé). +1.
Paul Tomblin
1
De rien. Voir aussi une autre bonne réponse: stackoverflow.com/questions/627661/writing-perl-code-in-utf8/… et rappelez-vous, TMTOWTDI. Et @Paul - si vous écrivez UTF-8 dans un fichier, vous devriez probablement utiliser binmode () sur ce descripteur de fichier et le rendre "approprié" UTF-8, mais si cela fonctionne ..
Chris Lutz
1
d'autres moyens: le pragma ouvert ( search.cpan.org/perldoc/open ), le commutateur -C ( perldoc.perl.org/perlrun.html#-C )
ysth
1
FWIW en est la raison: les chaînes qui ne contiennent que des caractères latin1 (ISO-8859-1), bien qu'elles soient plus ou moins stockées dans utf8, seront affichées par défaut en latin1. De cette façon, les scripts d'une ère pré-unicode fonctionnent toujours de la même manière, même avec un perl compatible Unicode.
mirod
3
Le pragma utf8 ne vous permet pas d'écrire votre source en UNICODE, il force la compréhension de votre source dans l'encodage UTF-8 (ou UTF-EBCDIC) d'UNICODE, une distinction importante.
Chas. Owens
83

Vous pouvez utiliser le pragma ouvert .

Pour par exemple. ci-dessous définit STDOUT, STDIN & STDERR pour utiliser UTF-8 ....

use open qw/:std :utf8/;
Draegtun
la source
1
BTW ... je vous ai donné +1. Je pense que binmode (STDOUT, ': utf8') est probablement plus correct dans cette situation. "use open" a d'autres bonnes utilisations mais je n'arrive pas à trouver comment vous pouvez le configurer pour encoder uniquement STDOUT?
draegtun
66

TMTOWTDI , a choisi la méthode qui correspond le mieux à votre façon de travailler. J'utilise la méthode de l'environnement pour ne pas avoir à y penser.

Dans l' environnement :

export PERL_UNICODE=SDL

sur la ligne de commande :

perl -CSDL -le 'print "\x{1815}"';

ou avec binmode :

binmode(STDOUT, ":utf8");          #treat as if it is UTF-8
binmode(STDIN, ":encoding(utf8)"); #actually check if it is UTF-8

ou avec PerlIO :

open my $fh, ">:utf8", $filename
    or die "could not open $filename: $!\n";

open my $fh, "<:encoding(utf-8)", $filename
    or die "could not open $filename: $!\n";

ou avec le pragma ouvert :

use open ":encoding(utf8)";
use open IN => ":encoding(utf8)", OUT => ":utf8";
Chas. Owens
la source
1
+1 pour une réponse complète; notez que cela SDLest implicite à la fois avec -Cet PERL_UNICODE. Le use open ':locale'pragma mérite également d'être mentionné, car il est l'équivalent dans le script de -Cet export PER_UNICODE=. Chacun de ces 3 vous donnera le support UTF8 pour tous les flux d'entrée et de sortie (qu'il s'agisse de fichiers ou de stdin / stdout / stderr), en supposant que les paramètres régionaux de votre environnement sont basés sur UTF8. Enfin, pour traiter également le code source comme UTF8, utilisez le use utf8;pragma.
mklement0
perl -Mutf8 -CSDL -e '...'permet de consommer / sortir UTF-8 ainsi que d'utiliser des littéraux UTF-8 à l'intérieur, -epar exemple pour le dossier d'un pauvre homme:perl -Mutf8 -CASDL -pe 'y/āáǎàēéěèīíǐìōóǒòūúǔùǖǘǚǜĀÁǍÀĒÉĚÈĪÍǏÌŌÓǑÒŪÚǓÙǕǗǙǛ/aaaaeeeeiiiioooouuuuüüüüAAAAEEEEIIIIOOOOUUUUÜÜÜÜ/'
vladr
0

Merci, enfin obtenu une solution pour ne pas mettre utf8 :: encoder partout dans le code. Pour synthétiser et compléter pour d'autres cas, comme écrire et lire des fichiers dans utf8 et fonctionne également avec LoadFile d'un fichier YAML dans utf8

use utf8;
use open ':encoding(utf8)';
binmode(STDOUT, ":utf8");

open(FH, ">test.txt"); 
print FH "something éá";

use YAML qw(LoadFile Dump);
my $PUBS = LoadFile("cache.yaml");
my $f = "2917";
my $ref = $PUBS->{$f};
print "$f \"".$ref->{name}."\" ". $ref->{primary_uri}." ";

où cache.yaml est:

---
2917:
  id: 2917
  name: Semanário
  primary_uri: 2917.xml
Sérgio
la source
-3

faire dans votre shell: $ env | grep LANG

Cela montrera probablement que votre shell n'utilise pas de paramètres régionaux utf-8.

nxadm
la source
En fait, il était réglé sur utf-8. Le problème était que je sortais vers STDOUT sans définir binmode sur utf-8;
2
Ce serait une préoccupation orthogonale. Vous avez besoin de votre script Perl pour générer des données correctes avant de vous soucier de la façon dont votre émulateur de terminal les interprète.
jrockway