¿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.


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.


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/;

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

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

-3

hacer en su shell: $ env | grep LANG

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


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
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.