2013-03-04 9 views
62

Jeżeli uruchomić następujące Perl program:Użycie "użyj utf8;" daje mi 'szeroki znak w druku'

perl -e 'use utf8; print "鸡\n";' 

uzyskać to ostrzeżenie:

Wide character in print at -e line 1. 

Jeśli uruchomić ten program Perl:

perl -e 'print "鸡\n";' 

Nie otrzymuję ostrzeżenia.

Myślałem, że use utf8 było wymagane do używania znaków UTF-8 w skrypcie Perla. Dlaczego to nie działa i jak mogę to naprawić? Używam Perl 5.16.2. Mam taki sam problem, jeśli znajduje się on w pliku, zamiast być jednym linijkiem w wierszu poleceń.

+3

"Dlaczego to nie działa?" To * działa *, ale to było moje doświadczenie z Unicode, że istnieje wiele bardzo zepsutych programów, które * wyglądają tak, jakby działały. Kiedy naprawisz jedną rzecz, czyniąc kod nieco mniej błędnym, wyniki wydają się dużo gorsze. Dopiero po naprawieniu * ostatniej * części wszystko wygląda dobrze. – hobbs

+0

Zwykle naprawiane przez ustawienie wyjściowego uchwytu na 'binmode' z odpowiednim kodowaniem ... http://albertech.blogspot.com/2017/04/fix-annoying-wide-character-in-print.html – jar

Odpowiedz

88

Bez use utf8 Perl interpretuje twój ciąg jako ciąg znaków jednobajtowych. Istnieją cztery bajty w Twojej ciąg, jak widać z tego:

$ perl -E 'say join ":", map { ord } split //, "鸡\n";' 
233:184:161:10 

Pierwsze trzy bajty tworzą swoją postać, ostatni jest line-feed.

Połączenie z print wysyła te cztery znaki do STDOUT. Twoja konsola następnie opracuje sposób wyświetlania tych znaków. Jeśli konsola jest skonfigurowana do używania UTF8, to zinterpretuje te trzy bajty jako swój pojedynczy znak i to jest to, co jest wyświetlane.

Jeśli dodamy moduł utf8, wszystko wygląda inaczej. W takim przypadku Perl interpretuje twój ciąg jako tylko dwa znaki.

$ perl -Mutf8 -E 'say join ":", map { ord } split //, "鸡\n";' 
40481:10 

Domyślnie warstwa IO Perla zakłada, że ​​działa ze znakami jednobajtowymi. Więc kiedy próbujesz wydrukować wielobajtową postać, Perl myśli, że coś jest nie tak i daje ci ostrzeżenie. Jak zawsze, możesz uzyskać więcej wyjaśnień tego błędu, włączając w to use diagnostics. Będzie to powiedzieć:

(S utf8) Perl spotkał szeroki charakter (> 255), gdy nie spodziewałem jeden. To ostrzeżenie jest domyślnie włączone dla I/O (np. Drukowanie). Najprostszym sposobem, aby wyciszyć to ostrzeżenie, jest dodanie warstwy: utf8 do danych wyjściowych , np. binmode STDOUT, ": utf8". Innym sposobem na wyłączenie ostrzeżenia jest dodanie ostrzeżenia "utf8"; ale często jest to bliższe oszustwom z . Ogólnie rzecz biorąc, należy jawnie oznaczyć uchwyt pliku za pomocą kodowania, patrz tryb otwarty i perlfunc/bin.

Jak inni podkreślili, musisz powiedzieć Perlowi, aby zaakceptował wielobajtowe wyjście. Istnieje wiele sposobów, aby to zrobić (patrz: przykłady Perl Unicode Tutorial). Jednym z najprostszych sposobów jest użycie flagi linii komend -CS - która mówi trzem standardowym uchwytom plików (STDIN, STDOUT i STDERR), aby poradzić sobie z UTF8.

$ perl -Mutf8 -e 'print "鸡\n";' 
Wide character in print at -e line 1. 
鸡 

vs

$ perl -Mutf8 -CS -e 'print "鸡\n";' 
鸡 

Unicode jest duże i złożone zagadnienie. Jak widzieliśmy, wiele prostych programów wydaje się robić to, co trzeba, ale z niewłaściwych powodów. Kiedy zaczniesz naprawiać część programu, rzeczy często będą się pogarszać, dopóki nie naprawisz wszystkich programu.

+0

Jak przeliterować "-Mutf8', jeśli nie w jednym perlu liniowym? –

+0

@LeiYang: 'use utf8;' –

60

Wszystko wskazuje na to, że kod Perl jest kodowany przy użyciu UTF-8. Trzeba powiedzieć Perl jak zakodować tekst:

use open ':std', ':encoding(UTF-8)'; 
+0

Dzięki, działa to dobrze w przypadku programów przechowywanych w plikach, w przeciwieństwie do jedno-liniowych w linii poleceń, które obejmuje odpowiedź @ DaveCross. – Samadi

11

można zbliżyć się do „po prostu zrobić utf8 wszędzie” za pomocą modułu CPAN utf8::all.

Kiedy print otrzymuje coś, że nie można drukować (znak większy niż 255, gdy nie :encoding warstwa jest), to zakłada się, że ma na celu zakodowania go za pomocą UTF-8. Robi to po ostrzeżeniu o problemie.

12

Koduje wszystkie standardowe wyjście jako UTF-8:

binmode STDOUT, ":utf8"; 
3

Można to wykorzystać,

perl -CS filename. 

również kończy się ten błąd.

1

W hiszpańskim można znaleźć ten błąd, gdy przy rozpoczęciu korzystania z:

use utf8; 

Twój kodowanie redaktor jest w innym kodowaniu. To, co widzisz w edytorze, nie jest tym, co robi Perl. Aby rozwiązać ten błąd, po prostu zmień kodowanie edytora na Unicode/UTF-8.

+1

Nie. To nie jest przyczyną błędu. Kod został poprawnie zakodowany jako UTF8, ale uchwyt pliku wyjściowego nie wiedział o tym. –

Powiązane problemy