Come posso produrre UTF-8 da Perl?


110

Sto cercando di scrivere uno script Perl usando il pragma "utf8" e ottengo risultati inaspettati. Sto usando Mac OS X 10.5 (Leopard) e sto modificando con TextMate. Tutte le mie impostazioni sia per il mio editor che per il sistema operativo sono predefinite per scrivere file in formato utf-8.

Tuttavia, quando inserisco quanto segue in un file di testo, lo salvo come ".pl" e lo eseguo, ottengo il simpatico "rombo con un punto interrogativo" al posto dei caratteri non ASCII.

#!/usr/bin/env perl -w

use strict;
use utf8;

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

Hai idea di cosa sto sbagliando? Mi aspetto di ottenere 'Çirçös' nell'output, ma invece ottengo ' ir s'.


1
Forse non è il programma .. penso che sia la tua shell o il tuo editor che esegue l'output
n00ki3

Tutte le risposte rispondono correttamente alla tua domanda su come impostarlo esplicitamente su UTF8. Penso che dovresti regolare le impostazioni locali del tuo terminale come mostrato in stackoverflow.com/a/14405949/498634 . Il terminale potrebbe non essere impostato su UTF8 e quindi i dati scritti su STDOUT in UTF8 verranno codificati in modo errato !
Daniel Böhmer

Ottima risposta su come lavorare con utf8:
Eugen Konkov

Risposte:


160

use utf8;non abilita l' output Unicode - ti permette di digitare Unicode nel tuo programma. Aggiungi questo al programma, prima della tua print()dichiarazione:

binmode(STDOUT, ":utf8");

Vedi se questo aiuta. Questo dovrebbe produrre STDOUToutput in UTF-8 invece che in ASCII ordinario.


Non lo sapevo (ho solo inserito UTF8 in un database, mai stampato). +1.
Paul Tomblin

1
Prego. Vedere anche un'altra risposta corretta: stackoverflow.com/questions/627661/writing-perl-code-in-utf8/... e ricordare, TMTOWTDI. E @Paul - se stai scrivendo UTF-8 su un file, dovresti probabilmente usare binmode () su quel filehandle e renderlo "corretto" UTF-8, ma se funziona ..
Chris Lutz

1
altri modi: il pragma aperto ( search.cpan.org/perldoc/open ), l'interruttore -C ( perldoc.perl.org/perlrun.html#-C )
ysth

1
FWIW qui è il motivo: le stringhe che contengono solo caratteri latin1 (ISO-8859-1), nonostante siano memorizzate più o meno in utf8, verranno emesse come latin1 per impostazione predefinita. In questo modo gli script di un'era pre-unicode funzionano ancora allo stesso modo, anche con un perl compatibile con unicode.
mirod

3
Il pragma utf8 non ti consente di scrivere la tua fonte in UNICODE, costringe a capire la tua fonte nella codifica UTF-8 (o UTF-EBCDIC) di UNICODE, una distinzione importante.
Chas. Owens

83

Puoi usare il pragma aperto .

Per es. sotto imposta STDOUT, STDIN e STDERR per usare UTF-8 ....

use open qw/:std :utf8/;

1
BTW ... ti ho dato +1. Penso che binmode (STDOUT, ': utf8') sia probabilmente più corretto in questa situazione. "use open" ha altri buoni usi ma non riesco a trovare come puoi impostarlo per codificare solo STDOUT?
draegtun

66

TMTOWTDI , ha scelto il metodo che meglio si adatta al tuo lavoro. Uso il metodo ambientale quindi non devo pensarci.

In ambiente :

export PERL_UNICODE=SDL

sulla riga di 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 il pragma aperto :

use open ":encoding(utf8)";
use open IN => ":encoding(utf8)", OUT => ":utf8";

1
+1 per una risposta esauriente; nota che SDLè implicito sia con -Cche PERL_UNICODE. Il use open ':locale'pragma è anche degno di nota, perché è l'equivalente in-script di -Ce export PER_UNICODE=. Ognuno di questi 3 fornirà il supporto UTF8 per tutti i flussi di input e output (file o stdin / stdout / stderr), assumendo che la locale del tuo ambiente sia basata su UTF8. Infine, per trattare anche il codice sorgente come UTF8, usa il use utf8;pragma.
mklement0

perl -Mutf8 -CSDL -e '...'consente di consumare / produrre UTF-8 e utilizzare i valori letterali UTF-8 all'interno, -ead esempio, per la cartella dei casi di un povero:perl -Mutf8 -CASDL -pe 'y/āáǎàēéěèīíǐìōóǒòūúǔùǖǘǚǜĀÁǍÀĒÉĚÈĪÍǏÌŌÓǑÒŪÚǓÙǕǗǙǛ/aaaaeeeeiiiioooouuuuüüüüAAAAEEEEIIIIOOOOUUUUÜÜÜÜ/'
vladr


0

Grazie, finalmente ho una soluzione per non mettere utf8 :: encode in tutto il codice. Per sintetizzare e completare per altri casi, come scrivere e leggere file in utf8 e funziona anche con LoadFile di un file YAML in 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}." ";

dove cache.yaml è:

---
2917:
  id: 2917
  name: Semanário
  primary_uri: 2917.xml

-3

fai nella tua shell: $ env | grep LANG

Questo probabilmente mostrerà che la tua shell non sta usando una locale utf-8.


In realtà, era impostato su utf-8. Il problema era che stavo eseguendo l'output su STDOUT senza impostare binmode su utf-8;

2
Questa sarebbe una preoccupazione ortogonale. Hai bisogno del tuo script Perl per produrre dati corretti prima di poterti preoccupare di come il tuo emulatore di terminale li interpreta.
jrockway
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.