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”.


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.


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/;

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

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

-3

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

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


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,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.