Uso de 'use utf8;' me da 'carácter ancho en la impresión'

86

Si ejecuto el siguiente programa Perl:

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

Recibo esta advertencia:

Wide character in print at -e line 1.

Si ejecuto este programa Perl:

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

No recibo ninguna advertencia.

Pensé que use utf8era necesario utilizar caracteres UTF-8 en un script de Perl. ¿Por qué no funciona y cómo puedo solucionarlo? Estoy usando Perl 5.16.2. Tengo el mismo problema si esto está en un archivo en lugar de ser una línea en la línea de comando.

Eric Johnson
fuente
3
"¿Por qué esto no funciona?" Se hace el trabajo, pero ha sido mi experiencia con Unicode que hay una gran cantidad de programas muy rotas por ahí que mirada como si estuvieran trabajando. Cuando arreglas algo, haciendo que el código sea un poco menos incorrecto, los resultados parecen mucho peores. Solo cuando arreglas la última parte, todo vuelve a verse bien.
hobbs

Respuestas:

110

Sin use utf8Perl interpreta su cadena como una secuencia de caracteres de un solo byte. Hay cuatro bytes en su cadena como puede ver en esto:

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

Los primeros tres bytes forman tu personaje, el último es el salto de línea.

La llamada a printenvía estos cuatro caracteres a STDOUT. Luego, su consola averigua cómo mostrar estos caracteres. Si su consola está configurada para usar UTF8, interpretará esos tres bytes como su único carácter y eso es lo que se muestra.

Si agregamos en el utf8módulo, las cosas son diferentes. En este caso, Perl interpreta su cadena como solo dos caracteres.

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

Por defecto, la capa IO de Perl asume que está trabajando con caracteres de un solo byte. Entonces, cuando intenta imprimir un carácter de varios bytes, Perl piensa que algo anda mal y le da una advertencia. Como siempre, puede obtener más explicación de este error si incluye use diagnostics. Dirá esto:

(S utf8) Perl encontró un carácter amplio (> 255) cuando no esperaba uno. Esta advertencia está activada de forma predeterminada para E / S (como impresión). La forma más fácil de silenciar esta advertencia es simplemente agregar la capa: utf8 a la salida, por ejemplo, binmode STDOUT, ': utf8'. Otra forma de desactivar la advertencia es no agregar advertencias 'utf8'; pero eso suele estar más cerca de hacer trampa. En general, se supone que debe marcar explícitamente el identificador de archivo con una codificación, consulte open y perlfunc / binmode.

Como otros han señalado, debe indicarle a Perl que acepte la salida de varios bytes. Hay muchas formas de hacer esto (consulte el Tutorial de Perl Unicode para ver algunos ejemplos). Una de las formas más sencillas es usar el -CSindicador de línea de comando, que le dice a los tres identificadores de archivos estándar (STDIN, STDOUT y STDERR) que se ocupen de UTF8.

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

vs

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

Unicode es un área grande y compleja. Como ha visto, muchos programas simples parecen hacer lo correcto, pero por razones equivocadas. Cuando comience a arreglar parte del programa, las cosas a menudo empeorarán hasta que haya arreglado todo el programa.

Dave Cross
fuente
¿Cómo se escribe -Mutf8si no en una sola línea perl?
Lei Yang
@LeiYang:use utf8;
Dave Cross
80

Todo lo que use utf8;hace es decirle a Perl que el código fuente está codificado usando UTF-8. Necesita decirle a Perl cómo codificar su texto:

use open ':std', ':encoding(UTF-8)';
ikegami
fuente
Gracias, esto funciona bien para los programas almacenados en archivos, a diferencia de las frases breves en la línea de comando, que cubre la respuesta de @ DaveCross.
vktec
19

Codifique toda la salida estándar como UTF-8:

binmode STDOUT, ":utf8";
Boris Ivanov
fuente
2
use open ':std', ':encoding(UTF-8)';como lo propone otra respuesta, hace esto para STDOUT pero también marca STDERR y STDIN como UTF-8, por lo que obtiene tres por el precio de una declaración. Véase también stackoverflow.com/a/42194059
Stephen Ostermiller
De acuerdo. Esto es incluso mejor.
Boris Ivanov
14

Puede acercarse a "simplemente hacer utf8 en todas partes" utilizando el módulo CPAN utf8::all.

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

Cuando printrecibe algo que no puede imprimir (carácter mayor a 255 cuando no :encodingse proporciona ninguna capa), se supone que pretendía codificarlo usando UTF-8. Lo hace después de advertir sobre el problema.

Joel Berger
fuente
5

Puedes usar esto,

perl -CS filename.

También terminará ese error.

Karthikeyan.RS
fuente
solo esto ayudó
muenalan
0

En español puede encontrar este error al lado de comenzar a usar:

use utf8;

La codificación de su editor tiene una codificación diferente. Entonces, lo que ves en el editor no es lo que hace Perl. Para resolver ese error, simplemente cambie la codificación del editor a Unicode / UTF-8 .

DiegoAr
fuente
1
No. Esto no es lo que estaba causando el error. El código estaba codificado correctamente como UTF8, pero el identificador del archivo de salida no sabía que lo era.
Dave Cross