Verwendung von 'use utf8;' gibt mir 'Breites Zeichen im Druck'

86

Wenn ich das folgende Perl-Programm ausführe:

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

Ich bekomme diese Warnung:

Wide character in print at -e line 1.

Wenn ich dieses Perl-Programm ausführe:

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

Ich bekomme keine Warnung.

Ich dachte, es use utf8sei erforderlich, UTF-8-Zeichen in einem Perl-Skript zu verwenden. Warum funktioniert das nicht und wie kann ich es beheben? Ich benutze Perl 5.16.2. Ich habe das gleiche Problem, wenn dies in einer Datei ist, anstatt ein Einzeiler in der Befehlszeile zu sein.

Eric Johnson
quelle
3
"Warum funktioniert das nicht?" Es funktioniert , aber es ist meine Erfahrung mit Unicode, dass es viele sehr kaputte Programme gibt, die so aussehen, als würden sie funktionieren. Wenn Sie eine Sache beheben und den Code etwas weniger falsch machen, scheinen die Ergebnisse viel schlechter zu sein. Erst wenn Sie den letzten Teil reparieren , sieht alles wieder gut aus.
Hobbs
1
Normalerweise behoben durch die Einstellung des Ausgabehandles auf binmodemit der richtigen Codierung ... albertech.blogspot.com/2017/04/…
jar

Antworten:

110

Ohne use utf8Perl wird Ihre Zeichenfolge als Folge von Einzelbytezeichen interpretiert. Ihre Zeichenfolge enthält vier Bytes, wie Sie sehen können:

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

Die ersten drei Bytes bilden Ihren Charakter, das letzte ist der Zeilenvorschub.

Der Aufruf printzum Senden dieser vier Zeichen an STDOUT. Ihre Konsole ermittelt dann, wie diese Zeichen angezeigt werden. Wenn Ihre Konsole auf UTF8 eingestellt ist, interpretiert sie diese drei Bytes als Ihr einzelnes Zeichen, und das wird angezeigt.

Wenn wir das utf8Modul hinzufügen , sind die Dinge anders. In diesem Fall interpretiert Perl Ihre Zeichenfolge als nur zwei Zeichen.

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

Standardmäßig geht die E / A-Ebene von Perl davon aus, dass sie mit Einzelbyte-Zeichen arbeitet. Wenn Sie also versuchen, ein Multi-Byte-Zeichen zu drucken, denkt Perl, dass etwas nicht stimmt, und gibt Ihnen eine Warnung aus. Wie immer können Sie weitere Erklärungen für diesen Fehler erhalten, indem Sie einschließen use diagnostics. Es wird folgendes sagen:

(S utf8) Perl traf einen breiten Charakter (> 255), als er keinen erwartete. Diese Warnung ist standardmäßig für E / A aktiviert (wie Drucken). Der einfachste Weg, diese Warnung zu beruhigen, besteht darin, der Ausgabe die Ebene: utf8 hinzuzufügen, z. B. binmode STDOUT, ': utf8'. Eine andere Möglichkeit, die Warnung auszuschalten, besteht darin, keine Warnungen 'utf8' hinzuzufügen. aber das ist oft näher am betrügen. Im Allgemeinen sollten Sie das Dateihandle explizit mit einer Codierung markieren, siehe open und perlfunc / binmode.

Wie andere bereits betont haben, müssen Sie Perl anweisen, eine Mehrbyte-Ausgabe zu akzeptieren. Es gibt viele Möglichkeiten, dies zu tun ( einige Beispiele finden Sie im Perl Unicode-Tutorial ). Eine der einfachsten Möglichkeiten ist die Verwendung des -CSBefehlszeilenflags, mit dem die drei Standard-Dateihandles (STDIN, STDOUT und STDERR) angewiesen werden, mit UTF8 umzugehen.

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

vs.

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

Unicode ist ein großer und komplexer Bereich. Wie Sie gesehen haben, scheinen viele einfache Programme das Richtige zu tun, aber aus den falschen Gründen. Wenn Sie anfangen, einen Teil des Programms zu reparieren, wird es oft schlimmer, bis Sie das gesamte Programm repariert haben .

Dave Cross
quelle
Wie buchstabieren Sie, -Mutf8wenn nicht in einem Liner Perl?
Lei Yang
@LeiYang:use utf8;
Dave Cross
77

Sie use utf8;müssen Perl lediglich mitteilen, dass der Quellcode mit UTF-8 codiert ist. Sie müssen Perl mitteilen, wie Sie Ihren Text codieren sollen:

use open ':std', ':encoding(UTF-8)';
Ikegami
quelle
Vielen Dank, dies funktioniert gut für Programme, die in Dateien gespeichert sind, im Gegensatz zu Einzeilern in der Befehlszeile, die in der Antwort von @ DaveCross behandelt werden.
vktec
19

Codieren Sie alle Standardausgaben als UTF-8:

binmode STDOUT, ":utf8";
Boris Ivanov
quelle
2
use open ':std', ':encoding(UTF-8)';Wie in einer anderen Antwort vorgeschlagen, gilt dies für STDOUT, markiert jedoch auch STDERR und STDIN als UTF-8, sodass Sie drei für den Preis einer Anweisung erhalten. Siehe auch stackoverflow.com/a/42194059
Stephen Ostermiller
Zustimmen. Das ist noch besser.
Boris Ivanov
14

Mit dem CPAN-Modul können Sie sich "einfach überall utf8 machen" nähern utf8::all.

perl -Mutf8::all -e 'print "鸡\n";'

Wenn printetwas empfangen wird, das nicht gedruckt werden kann (Zeichen größer als 255, wenn keine :encodingEbene bereitgestellt wird), wird davon ausgegangen, dass Sie es mit UTF-8 codieren möchten. Dies geschieht nach Warnung vor dem Problem.

Joel Berger
quelle
5

Sie können dies verwenden,

perl -CS filename.

Dieser Fehler wird ebenfalls beendet.

Karthikeyan.RS
quelle
nur das half
muenalan
0

Auf Spanisch können Sie diesen Fehler finden, wenn Sie neben der Verwendung beginnen:

use utf8;

Ihre Editor-Codierung hat eine andere Codierung. Was Sie also im Editor sehen, ist nicht das, was Perl tut. Um diesen Fehler zu beheben, ändern Sie einfach die Editor-Codierung in Unicode / UTF-8 .

DiegoAr
quelle
1
Nein, das hat den Fehler nicht verursacht. Der Code wurde ordnungsgemäß als UTF8 codiert, aber das Ausgabe-Dateihandle wusste nicht, dass dies der Fall war.
Dave Cross