Como posso gerar UTF-8 do Perl?

110

Estou tentando escrever um script Perl usando o pragma "utf8" e estou obtendo resultados inesperados. Estou usando o Mac OS X 10.5 (Leopard) e estou editando com o TextMate. Todas as minhas configurações para meu editor e sistema operacional são padronizadas para gravar arquivos no formato utf-8.

No entanto, ao inserir o seguinte em um arquivo de texto, salvá-lo como ".pl" e executá-lo, recebo o amigável "diamante com um ponto de interrogação" no lugar dos caracteres não ASCII.

#!/usr/bin/env perl -w

use strict;
use utf8;

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

Alguma ideia do que estou fazendo de errado? Espero obter 'Çirçös' na saída, mas recebo ' ir s' em vez disso.

dda
fonte
1
Talvez não seja o programa .. eu acho que é o seu shell ou seu editor que faz a saída
n00ki3
Todas as respostas respondem corretamente à sua pergunta sobre como configurá-lo explicitamente para UTF8. Acho que você deve se ajustar às configurações de localidade do seu terminal, conforme mostrado em stackoverflow.com/a/14405949/498634 . O terminal pode não ser definido como UTF8 e os dados gravados em STDOUT em UTF8 serão codificados incorretamente !
Daniel Böhmer
Ótima resposta como trabalhar com utf8:
Eugen Konkov

Respostas:

160

use utf8;não ativa a saída Unicode - permite que você digite Unicode em seu programa. Adicione isto ao programa, antes de sua print()declaração:

binmode(STDOUT, ":utf8");

Veja se isso ajuda. Isso deve produzir STDOUTsaída em UTF-8 em vez de ASCII comum.

Chris Lutz
fonte
Eu não sabia disso (só coloquei UTF8 em um banco de dados, nunca imprimi). +1.
Paul Tomblin,
1
De nada. Veja também outra resposta correta: stackoverflow.com/questions/627661/writing-perl-code-in-utf8/… e lembre-se, TMTOWTDI. E @Paul - se você está gravando UTF-8 em um arquivo, você provavelmente deve usar binmode () nesse identificador de arquivo e torná-lo UTF-8 "adequado", mas se funcionar ..
Chris Lutz,
1
outras maneiras: o pragma aberto ( search.cpan.org/perldoc/open ), a opção -C ( perldoc.perl.org/perlrun.html#-C )
ysth
1
FWIW aqui está o motivo: strings que contêm apenas caracteres latin1 (ISO-8859-1), apesar de serem armazenados mais ou menos em utf8, serão reproduzidas como latin1 por padrão. Desta forma, os scripts de uma era pré-Unicode ainda funcionam da mesma forma, mesmo com um perl compatível com Unicode.
mirod
3
O pragma utf8 não permite que você escreva sua fonte em UNICODE, ele força o entendimento de sua fonte na codificação UTF-8 (ou UTF-EBCDIC) de UNICODE, uma distinção importante.
Chas. Owens,
83

Você pode usar o pragma aberto .

Por exemplo. abaixo define STDOUT, STDIN e STDERR para usar UTF-8 ....

use open qw/:std :utf8/;
draegtun
fonte
1
BTW ... eu dei a u +1. Acho que binmode (STDOUT, ': utf8') é provavelmente mais correto nessa situação. "use open" tem outros bons usos, mas não consigo descobrir como você pode configurá-lo para codificar apenas STDOUT?
draegtun
66

TMTOWTDI , escolheu o método que melhor se adapta ao seu trabalho. Eu uso o método do ambiente, então não preciso pensar sobre isso.

No meio ambiente :

export PERL_UNICODE=SDL

na linha de comando :

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

ou com binmode :

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

ou com 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 com o pragma aberto :

use open ":encoding(utf8)";
use open IN => ":encoding(utf8)", OUT => ":utf8";
Chas. Owens
fonte
1
+1 para uma resposta abrangente; observe que SDLestá implícito em -Ce PERL_UNICODE. O use open ':locale'pragma também vale a pena ser mencionado, porque é o equivalente no script de -Ce export PER_UNICODE=. Qualquer um desses 3 fornecerá suporte UTF8 para todos os fluxos de entrada e saída (sejam arquivos ou stdin / stdout / stderr), assumindo que a localidade do seu ambiente é baseada em UTF8. Finalmente, para tratar também o código- fonte como UTF8, use o use utf8;pragma.
mklement0
perl -Mutf8 -CSDL -e '...'permite consumir / produzir UTF-8 , bem como usar literais UTF-8 dentro, -epor exemplo, para a pasta do caso de um homem pobre:perl -Mutf8 -CASDL -pe 'y/āáǎàēéěèīíǐìōóǒòūúǔùǖǘǚǜĀÁǍÀĒÉĚÈĪÍǏÌŌÓǑÒŪÚǓÙǕǗǙǛ/aaaaeeeeiiiioooouuuuüüüüAAAAEEEEIIIIOOOOUUUUÜÜÜÜ/'
vladr
1

Você também quer dizer que as strings em seu código são utf-8. Consulte Por que o Perl moderno evita UTF-8 por padrão? . Portanto, defina não só, PERL_UNICODE=SDALmas também PERL5OPT=-Mutf8.

Hans Ginzel
fonte
0

Obrigado, finalmente consegui uma solução para não colocar utf8 :: encode em todo o código. Para sintetizar e completar para outros casos, como escrever e ler arquivos em utf8 e também trabalhar com LoadFile de um arquivo YAML em 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}." ";

onde cache.yaml é:

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

faça no seu shell: $ env | grep LANG

Isso provavelmente mostrará que seu shell não está usando uma localidade utf-8.

nxadm
fonte
Na verdade, ele foi definido como utf-8. O problema era que eu estava enviando para STDOUT sem definir binmode para utf-8;
2
Esta seria uma preocupação ortogonal. Você precisa que seu script Perl produza dados corretos antes de se preocupar com a interpretação de seu emulador de terminal.
jrockway,