Bagaimana cara mengeluarkan UTF-8 dari Perl?

110

Saya mencoba menulis skrip Perl menggunakan pragma "utf8", dan saya mendapatkan hasil yang tidak diharapkan. Saya menggunakan Mac OS X 10.5 (Leopard), dan saya mengedit dengan TextMate. Semua pengaturan saya untuk editor dan sistem operasi saya secara default menulis file dalam format utf-8.

Namun, ketika saya memasukkan yang berikut ini ke dalam file teks, menyimpannya sebagai ".pl", dan menjalankannya, saya mendapatkan "berlian dengan tanda tanya" sebagai pengganti karakter non-ASCII.

#!/usr/bin/env perl -w

use strict;
use utf8;

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

Tahu apa yang saya lakukan salah? Saya berharap mendapatkan 'Çirçös' di output, tetapi saya mendapatkan ' ir s' sebagai gantinya.

dda
sumber
1
Mungkin ini bukan programnya .. saya pikir shell Anda atau editor Anda yang melakukan output
n00ki3
Semua jawaban menjawab dengan benar pertanyaan Anda bagaimana mengaturnya secara eksplisit ke UTF8. Saya pikir Anda harus menyesuaikan dengan pengaturan lokal terminal Anda seperti yang ditunjukkan di stackoverflow.com/a/14405949/498634 . Terminal mungkin tidak disetel ke UTF8 dan kemudian data yang ditulis ke STDOUT dalam UTF8 akan dienkode dengan tidak benar !
Daniel Böhmer
Jawaban yang bagus bagaimana bekerja dengan utf8:
Eugen Konkov

Jawaban:

160

use utf8;tidak mengaktifkan keluaran Unicode - ini memungkinkan Anda untuk mengetik Unicode dalam program Anda. Tambahkan ini ke program, sebelum print()pernyataan Anda :

binmode(STDOUT, ":utf8");

Lihat apakah itu membantu. Itu harus membuat STDOUTkeluaran dalam UTF-8, bukan ASCII biasa.

Chris Lutz
sumber
Saya tidak tahu tentang ini (saya hanya meletakkan UTF8 dalam database, tidak pernah mencetaknya). +1.
Paul Tomblin
1
Sama-sama. Lihat juga jawaban lain yang benar: stackoverflow.com/questions/627661/writing-perl-code-in-utf8/… dan ingat, TMTOWTDI. Dan @Paul - jika Anda menulis UTF-8 ke sebuah file, Anda mungkin harus menggunakan binmode () pada filehandle itu dan menjadikannya UTF-8 yang "layak", tetapi jika berhasil ..
Chris Lutz
1
cara lain: pragma terbuka ( search.cpan.org/perldoc/open ), tombol -C ( perldoc.perl.org/perlrun.html#-C )
ysth
1
Alasannya adalah FWIW: string yang hanya berisi karakter latin1 (ISO-8859-1), meskipun disimpan lebih atau kurang di utf8, akan menjadi keluaran latin1 secara default. Dengan cara ini skrip dari era pra-unicode masih berfungsi sama, bahkan dengan perl yang peka unicode.
mirod
3
Pragma utf8 tidak mengizinkan Anda menulis sumber dalam UNICODE, ini memaksa pemahaman tentang sumber Anda dalam pengkodean UTF-8 (atau UTF-EBCDIC) UNICODE, perbedaan penting.
Chas. Owens
83

Anda bisa menggunakan pragma terbuka .

Misalnya. di bawah ini menetapkan STDOUT, STDIN & STDERR untuk menggunakan UTF-8 ....

use open qw/:std :utf8/;
draegtun.dll
sumber
1
BTW ... Aku memberimu +1. Saya pikir binmode (STDOUT, ': utf8') mungkin lebih tepat dalam situasi ini. "gunakan terbuka" memiliki kegunaan lain yang baik tetapi saya tidak dapat menemukan bagaimana Anda dapat mengaturnya untuk hanya menyandikan STDOUT saja?
draegtun
66

TMTOWTDI , pilih metode yang paling sesuai dengan cara Anda bekerja. Saya menggunakan metode lingkungan jadi saya tidak perlu memikirkannya.

Di lingkungan :

export PERL_UNICODE=SDL

di baris perintah :

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

atau dengan binmode :

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

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

atau dengan pragma terbuka :

use open ":encoding(utf8)";
use open IN => ":encoding(utf8)", OUT => ":utf8";
Chas. Owens
sumber
1
1 untuk jawaban komprehensif; catatan yang SDLtersirat baik dengan -Cdan PERL_UNICODE. The use open ':locale'pragma juga layak disebutkan, karena itu adalah di-script setara -Cdan export PER_UNICODE=. Salah satu dari 3 ini akan memberi Anda dukungan UTF8 untuk semua aliran input dan output (baik file atau stdin / stdout / stderr), dengan asumsi lokal lingkungan Anda berbasis UTF8. Terakhir, untuk juga memperlakukan kode sumber sebagai UTF8, gunakan use utf8;pragma.
mklement0
perl -Mutf8 -CSDL -e '...'memungkinkan untuk mengkonsumsi / mengeluarkan UTF-8 serta menggunakan literal UTF-8 di dalam -emisalnya untuk folder kasus orang miskin:perl -Mutf8 -CASDL -pe 'y/āáǎàēéěèīíǐìōóǒòūúǔùǖǘǚǜĀÁǍÀĒÉĚÈĪÍǏÌŌÓǑÒŪÚǓÙǕǗǙǛ/aaaaeeeeiiiioooouuuuüüüüAAAAEEEEIIIIOOOOUUUUÜÜÜÜ/'
vladr
0

Terima kasih, akhirnya mendapat solusi untuk tidak meletakkan utf8 :: encode di seluruh kode. Untuk mensintesis dan menyelesaikan kasus lain, seperti menulis dan membaca file di utf8 dan juga bekerja dengan LoadFile dari file YAML di 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}." ";

di mana cache.yaml adalah:

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

lakukan di shell Anda: $ env | grep LANG

Ini mungkin akan menunjukkan bahwa shell Anda tidak menggunakan lokal utf-8.

nxadm
sumber
Sebenarnya, ini disetel ke utf-8. Masalahnya adalah saya mengeluarkan output ke STDOUT tanpa menyetel binmode ke utf-8;
2
Ini akan menjadi perhatian ortogonal. Anda memerlukan skrip Perl untuk mengeluarkan data yang benar sebelum Anda khawatir tentang bagaimana emulator terminal Anda menafsirkannya.
jrockway