¿Cómo puedo generar UTF-8 desde Perl?

110

Estoy intentando escribir un script en Perl usando el pragma "utf8" y obtengo resultados inesperados. Estoy usando Mac OS X 10.5 (Leopard) y estoy editando con TextMate. Todas mis configuraciones tanto para mi editor como para mi sistema operativo están predeterminadas para escribir archivos en formato utf-8.

Sin embargo, cuando ingreso lo siguiente en un archivo de texto, lo guardo como ".pl" y lo ejecuto, obtengo el "diamante con un signo de interrogación" descriptivo en lugar de los caracteres que no son ASCII.

#!/usr/bin/env perl -w

use strict;
use utf8;

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

¿Alguna idea de lo que estoy haciendo mal? Espero obtener 'Çirçös' en la salida, pero obtengo ' ir s' en su lugar.

dda
fuente
1
Tal vez no sea el programa ... creo que es su shell o su editor el que hace la salida
n00ki3
Todas las respuestas responden correctamente a su pregunta sobre cómo configurarlo explícitamente en UTF8. Creo que debería ajustarse a la configuración regional de su terminal como se muestra en stackoverflow.com/a/14405949/498634 . Es posible que el terminal no esté configurado en UTF8 y luego los datos escritos en STDOUT en UTF8 se codificarán incorrectamente .
Daniel Böhmer
Excelente respuesta a cómo trabajar con utf8:
Eugen Konkov

Respuestas:

160

use utf8;no habilita la salida Unicode - le permite escribir Unicode en su programa. Agregue esto al programa, antes de su print()declaración:

binmode(STDOUT, ":utf8");

Vea si eso ayuda. Eso debería STDOUTgenerar una salida en UTF-8 en lugar de ASCII ordinario.

Chris Lutz
fuente
No sabía sobre esto (solo he estado colocando UTF8 en una base de datos, nunca lo imprimí). +1.
Paul Tomblin
1
De nada. Consulte también otra respuesta correcta: stackoverflow.com/questions/627661/writing-perl-code-in-utf8/… y recuerde, TMTOWTDI. Y @Paul: si está escribiendo UTF-8 en un archivo, probablemente debería usar binmode () en ese identificador de archivo y convertirlo en UTF-8 "adecuado", pero si funciona ...
Chris Lutz
1
otras formas: el pragma abierto ( search.cpan.org/perldoc/open ), el interruptor -C ( perldoc.perl.org/perlrun.html#-C )
ysth
1
FWIW aquí está la razón: las cadenas que contienen solo caracteres latin1 (ISO-8859-1), a pesar de estar almacenadas más o menos en utf8, se generarán como latin1 por defecto. De esta forma, los scripts de una era anterior a Unicode siguen funcionando igual, incluso con un perl compatible con Unicode.
mirod
3
El pragma utf8 no le permite escribir su fuente en UNICODE, le obliga a comprender su fuente en la codificación UTF-8 (o UTF-EBCDIC) de UNICODE, una distinción importante.
Chas. Owens
83

Puede utilizar el pragma abierto .

Por ej. a continuación establece STDOUT, STDIN y STDERR para usar UTF-8 ....

use open qw/:std :utf8/;
draegtun
fuente
1
Por cierto ... te di +1. Creo que binmode (STDOUT, ': utf8') es probablemente más correcto en esta situación. "use open" tiene otros buenos usos, pero parece que no puedo encontrar cómo puede configurarlo para codificar solo STDOUT.
Draegtun
66

TMTOWTDI , eligió el método que mejor se adapta a su forma de trabajar. Utilizo el método del entorno para no tener que pensar en ello.

En el medio ambiente :

export PERL_UNICODE=SDL

en la línea de comando :

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

o con binmode :

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

o con 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";

o con el pragma abierto :

use open ":encoding(utf8)";
use open IN => ":encoding(utf8)", OUT => ":utf8";
Chas. Owens
fuente
1
+1 para una respuesta completa; tenga en cuenta que SDLestá implícito con -Cy PERL_UNICODE. El use open ':locale'pragma es también digno de mención, ya que es el equivalente en la escritura de -Cy export PER_UNICODE=. Cualquiera de estos 3 le dará soporte UTF8 para todos los flujos de entrada y salida (ya sean archivos o stdin / stdout / stderr), asumiendo que la configuración regional de su entorno está basada en UTF8. Finalmente, para tratar también el código fuente como UTF8, use use utf8;pragma.
mklement0
perl -Mutf8 -CSDL -e '...'permite consumir / generar UTF-8 , así como usar literales UTF-8 dentro, -epor ejemplo, para la carpeta del caso de un pobre:perl -Mutf8 -CASDL -pe 'y/āáǎàēéěèīíǐìōóǒòūúǔùǖǘǚǜĀÁǍÀĒÉĚÈĪÍǏÌŌÓǑÒŪÚǓÙǕǗǙǛ/aaaaeeeeiiiioooouuuuüüüüAAAAEEEEIIIIOOOOUUUUÜÜÜÜ/'
vladr
0

Gracias, finalmente obtuve una solución para no poner utf8 :: encode en todo el código. Para sintetizar y completar para otros casos, como escribir y leer archivos en utf8 y también funciona con LoadFile de un archivo YAML en 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}." ";

donde cache.yaml es:

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

hacer en su shell: $ env | grep LANG

Esto probablemente mostrará que su shell no está usando una configuración regional utf-8.

nxadm
fuente
En realidad, estaba configurado en utf-8. El problema era que estaba enviando a STDOUT sin configurar binmode en utf-8;
2
Esta sería una preocupación ortogonal. Necesita su secuencia de comandos de Perl para generar datos correctos antes de que pueda preocuparse por cómo su emulador de terminal los interpreta.
jrockway