Jak wyprowadzić UTF-8 z Perla?

110

Próbuję napisać skrypt Perla przy użyciu pragmy „utf8” i otrzymuję nieoczekiwane rezultaty. Używam systemu Mac OS X 10.5 (Leopard) i edytuję za pomocą TextMate. Wszystkie moje ustawienia zarówno mojego edytora, jak i systemu operacyjnego są domyślnie ustawione na zapisywanie plików w formacie utf-8.

Jednak kiedy wprowadzam następujące polecenie do pliku tekstowego, zapisuję go jako „.pl” i wykonuję, otrzymuję przyjazny „romb ze znakiem zapytania” zamiast znaków spoza zestawu ASCII.

#!/usr/bin/env perl -w

use strict;
use utf8;

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

Masz pojęcie, co robię źle? Spodziewam się, że na wyjściu pojawi się „Çirçös”, ale zamiast tego otrzymuję „ irçös”.

dda
źródło
1
Może to nie jest program .. Myślę, że jego powłokę oder edytorze który robi wyjście
n00ki3
Wszystkie odpowiedzi poprawnie odpowiadają na Twoje pytanie, jak ustawić jawnie na UTF8. Myślę, że powinieneś dostosować się do ustawień regionalnych swojego terminala, jak pokazano na stackoverflow.com/a/14405949/498634 . Terminal może nie być ustawiony na UTF8, a wtedy dane zapisane w STDOUT w UTF8 będą nieprawidłowo zakodowane !
Daniel Böhmer
Świetna odpowiedź, jak pracować z utf8:
Eugenem Konkovem

Odpowiedzi:

160

use utf8;nie włącza wyjścia Unicode - umożliwia wpisanie Unicode w programie. Dodaj to do programu, przed swoim print()oświadczeniem:

binmode(STDOUT, ":utf8");

Zobacz, czy to pomoże. To powinno dać STDOUTwyjście w UTF-8 zamiast zwykłego ASCII.

Chris Lutz
źródło
Nie wiedziałem o tym (tylko umieszczałem UTF8 w bazie danych, nigdy go nie drukowałem). +1.
Paul Tomblin,
1
Nie ma za co. Zobacz też inną poprawną odpowiedź: stackoverflow.com/questions/627661/writing-perl-code-in-utf8/ ... i pamiętaj, TMTOWTDI. I @Paul - jeśli piszesz UTF-8 do pliku, należy prawdopodobnie użyć BINMODE () na tej uchwytu pliku i sprawiają, że „właściwa” UTF-8, ale czy to działa ..
Chris Lutz
1
inne sposoby: otwarta pragma ( search.cpan.org/perldoc/open ), przełącznik -C ( perldoc.perl.org/perlrun.html#-C )
ysth
1
Przyczyną jest tutaj FWIW: łańcuchy zawierające tylko znaki latin1 (ISO-8859-1), mimo że są przechowywane mniej więcej w utf8, będą domyślnie wyświetlane jako latin1. W ten sposób skrypty z epoki sprzed wydania Unicode nadal działają tak samo, nawet z perlem obsługującym Unicode.
mirod
3
Pragma utf8 nie pozwala ci pisać źródła w UNICODE, wymusza zrozumienie twojego źródła w kodowaniu UTF-8 (lub UTF-EBCDIC) UNICODE, co jest ważną różnicą.
Chas. Owens
83

Możesz użyć otwartej pragmy .

Np. poniżej ustawia STDOUT, STDIN i STDERR do używania UTF-8 ....

use open qw/:std :utf8/;
draegtun
źródło
1
BTW ... dałem ci +1. Myślę, że binmode (STDOUT, ': utf8') jest prawdopodobnie bardziej poprawne w tej sytuacji. „użyj otwartego” ma inne dobre zastosowania, ale nie mogę znaleźć sposobu, w jaki można go ustawić na kodowanie tylko STDOUT?
draegtun
66

TMTOWTDI , wybierz metodę, która najlepiej pasuje do Twojego stylu pracy. Używam metody środowiskowej, więc nie muszę o tym myśleć.

W środowisku :

export PERL_UNICODE=SDL

w linii poleceń :

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

lub z binmode :

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

lub z 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";

lub z otwartą pragmą :

use open ":encoding(utf8)";
use open IN => ":encoding(utf8)", OUT => ":utf8";
Chas. Owens
źródło
1
+1 za wyczerpującą odpowiedź; zauważ, że SDLjest to implikowane zarówno w przypadku, jak -Ci PERL_UNICODE. use open ':locale'Pragma Warto również wspomnieć, ponieważ jest to równoważne-scenariusz -Ci export PER_UNICODE=. Każde z tych 3 zapewni obsługę UTF8 dla wszystkich strumieni wejściowych i wyjściowych (plików lub stdin / stdout / stderr), przy założeniu, że ustawienia regionalne twojego środowiska są oparte na UTF8. Wreszcie, aby traktować kod źródłowy również jako UTF8, użyj use utf8;pragmy.
mklement0
perl -Mutf8 -CSDL -e '...'pozwala konsumować / wyprowadzać UTF-8, a także używać literałów UTF-8 wewnątrz, -enp. dla folderu ze perl -Mutf8 -CASDL -pe 'y/āáǎàēéěèīíǐìōóǒòūúǔùǖǘǚǜĀÁǍÀĒÉĚÈĪÍǏÌŌÓǑÒŪÚǓÙǕǗǙǛ/aaaaeeeeiiiioooouuuuüüüüAAAAEEEEIIIIOOOOUUUUÜÜÜÜ/'
sprawami biedaka
0

Dzięki, w końcu znalazłem rozwiązanie, aby nie umieszczać utf8 :: encode w całym kodzie. Aby zsyntetyzować i uzupełnić w innych przypadkach, takich jak zapis i odczyt plików w utf8, a także działa z LoadFile pliku YAML w 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}." ";

gdzie cache.yaml to:

---
2917:
  id: 2917
  name: Semanário
  primary_uri: 2917.xml
Sérgio
źródło
-3

wykonaj w swojej powłoce: $ env | grep LANG

To prawdopodobnie pokaże, że Twoja powłoka nie używa ustawień regionalnych utf-8.

nxadm
źródło
Właściwie był ustawiony na utf-8. Problem polegał na tym, że wysyłałem do STDOUT bez ustawiania binmode na utf-8;
2
Byłby to problem ortogonalny. Potrzebujesz skryptu Perla do wysyłania poprawnych danych, zanim będziesz mógł się martwić o to, jak zinterpretuje je emulator terminala.
jrockway,