Uso de 'use utf8;' me dá 'Wide character in print'

86

Se eu executar o seguinte programa Perl:

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

Eu recebo este aviso:

Wide character in print at -e line 1.

Se eu executar este programa Perl:

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

Eu não recebo um aviso.

Achei que use utf8era necessário usar caracteres UTF-8 em um script Perl. Por que isso não funciona e como posso corrigir? Estou usando Perl 5.16.2. Eu tenho o mesmo problema se isso estiver em um arquivo em vez de ser um liner na linha de comando.

Eric Johnson
fonte
3
"Por que isso não funciona?" Ele faz o trabalho, mas tem sido minha experiência com Unicode que há um monte de programas muito quebradas lá fora, que olhar como eles estão trabalhando. Quando você corrige uma coisa, tornando o código um pouco menos errado, os resultados parecem muito piores. É apenas quando você conserta a última parte que tudo parece bom novamente.
hobbs

Respostas:

110

Sem use utf8Perl interpreta sua string como uma sequência de caracteres de byte único. Existem quatro bytes em sua string, como você pode ver:

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

Os primeiros três bytes constituem o seu personagem, o último é o feed de linha.

A chamada para printenvia esses quatro caracteres para STDOUT. Seu console então descobrirá como exibir esses personagens. Se o seu console estiver configurado para usar UTF8, ele interpretará esses três bytes como seu único caractere e é isso que é exibido.

Se adicionarmos o utf8módulo, as coisas são diferentes. Neste caso, Perl interpreta sua string como apenas dois caracteres.

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

Por padrão, a camada de E / S do Perl assume que está trabalhando com caracteres de byte único. Portanto, quando você tenta imprimir um caractere multibyte, o Perl pensa que algo está errado e lhe dá um aviso. Como sempre, você pode obter mais explicações para esse erro incluindo use diagnostics. Ele vai dizer o seguinte:

(S utf8) Perl encontrou um caractere largo (> 255) quando não estava esperando um. Este aviso é ativado por padrão para E / S (como impressão). A maneira mais fácil de silenciar esse aviso é simplesmente adicionar a camada: utf8 à saída, por exemplo, binmode STDOUT, ': utf8'. Outra maneira de desligar o aviso é não adicionar avisos 'utf8'; mas isso geralmente está mais perto de trapacear. Em geral, você deve marcar explicitamente o filehandle com uma codificação, consulte open e perlfunc / binmode.

Como outros indicaram, você precisa dizer ao Perl para aceitar a saída multibyte. Há muitas maneiras de fazer isso (veja o Tutorial do Perl Unicode para alguns exemplos). Uma das maneiras mais simples é usar o -CSsinalizador de linha de comando - que informa os três manipuladores de arquivos padrão (STDIN, STDOUT e STDERR) para lidar com UTF8.

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

vs

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

Unicode é uma área grande e complexa. Como você viu, muitos programas simples parecem fazer a coisa certa, mas pelos motivos errados. Quando você começa a consertar parte do programa, as coisas geralmente ficam piores até que você conserte todo o programa.

Dave Cross
fonte
Como soletrar -Mutf8se não em um perl forro?
Lei Yang de
@LeiYang:use utf8;
Dave Cross de
80

Tudo o que use utf8;faz é dizer ao Perl que o código-fonte está codificado usando UTF-8. Você precisa dizer ao Perl como codificar seu texto:

use open ':std', ':encoding(UTF-8)';
ikegami
fonte
Obrigado, isso funciona bem para programas armazenados em arquivos, ao contrário de one-liners na linha de comando, que a resposta de @ DaveCross cobre.
vktec
19

Codifique todas as saídas padrão como UTF-8:

binmode STDOUT, ":utf8";
Boris Ivanov
fonte
2
use open ':std', ':encoding(UTF-8)';conforme proposto por outra resposta, faz isso para STDOUT, mas também marca STDERR e STDIN como UTF-8, portanto, você obtém três pelo preço de uma instrução. Consulte também stackoverflow.com/a/42194059
Stephen Ostermiller
Aceita. Isso é ainda melhor.
Boris Ivanov
14

Você pode chegar perto de "apenas fazer utf8 em qualquer lugar" usando o módulo CPAN utf8::all.

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

Quando printrecebe algo que não pode imprimir (caractere maior que 255 quando nenhuma :encodingcamada é fornecida), ele assume que você pretendia codificá-lo usando UTF-8. Ele o faz, após avisar sobre o problema.

Joel Berger
fonte
5

Você pode usar isso,

perl -CS filename.

Isso também encerrará esse erro.

Karthikeyan.RS
fonte
só isso ajudou
muenalan
0

Em espanhol, você pode encontrar este erro ao lado de começar a usar:

use utf8;

A codificação do seu editor está em uma codificação diferente. Portanto, o que você vê no editor não é o que o Perl faz. Para resolver esse erro, basta alterar a codificação do editor para Unicode / UTF-8 .

DiegoAr
fonte
1
Não. Não era isso que estava causando o erro. O código foi devidamente codificado como UTF8, mas o manipulador de arquivos de saída não sabia disso.
Dave Cross