Wie kann ich UTF-8 von Perl ausgeben?

110

Ich versuche, ein Perl-Skript mit dem Pragma "utf8" zu schreiben, und erhalte unerwartete Ergebnisse. Ich verwende Mac OS X 10.5 (Leopard) und bearbeite mit TextMate. Alle meine Einstellungen für meinen Editor und mein Betriebssystem sind standardmäßig auf das Schreiben von Dateien im utf-8-Format eingestellt.

Wenn ich jedoch Folgendes in eine Textdatei eingebe, es als ".pl" speichere und ausführe, erhalte ich anstelle der Nicht-ASCII-Zeichen den freundlichen "Diamanten mit einem Fragezeichen".

#!/usr/bin/env perl -w

use strict;
use utf8;

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

Irgendeine Idee, was ich falsch mache? Ich erwarte 'Çirçös' in der Ausgabe, aber ich bekomme stattdessen ' ir s'.

dda
quelle
1
Vielleicht ist es nicht das Programm. Ich denke, es ist deine Shell oder dein Editor, der die Ausgabe macht
n00ki3
Alle Antworten beantworten Ihre Frage richtig, wie Sie sie explizit auf UTF8 setzen können. Ich denke, Sie sollten sich an die Gebietsschemaeinstellungen Ihres Terminals anpassen, wie in stackoverflow.com/a/14405949/498634 gezeigt . Das Terminal ist möglicherweise nicht auf UTF8 eingestellt, und dann werden in UTF8 in STDOUT geschriebene Daten falsch codiert !
Daniel Böhmer
Tolle Antwort, wie man arbeitet utf8:
Eugen Konkov

Antworten:

160

use utf8;aktiviert die Unicode- Ausgabe nicht - Sie können Unicode in Ihr Programm eingeben. Fügen Sie dies dem Programm vor Ihrer print()Aussage hinzu:

binmode(STDOUT, ":utf8");

Sehen Sie, ob das hilft. Das sollte die STDOUTAusgabe in UTF-8 anstelle von gewöhnlichem ASCII machen.

Chris Lutz
quelle
Ich wusste nichts davon (ich habe UTF8 nur in eine Datenbank gestellt und nie gedruckt). +1.
Paul Tomblin
1
Bitte. Siehe auch eine andere richtige Antwort: stackoverflow.com/questions/627661/writing-perl-code-in-utf8/… und denken Sie daran, TMTOWTDI. Und @Paul - wenn Sie UTF-8 in eine Datei schreiben, sollten Sie wahrscheinlich binmode () für dieses Dateihandle verwenden und es zu "richtigem" UTF-8 machen, aber wenn es funktioniert ..
Chris Lutz
1
andere Möglichkeiten: das offene Pragma ( search.cpan.org/perldoc/open ), der -C-Schalter ( perldoc.perl.org/perlrun.html#-C )
ysth
1
FWIW hier ist der Grund: Zeichenfolgen, die nur lateinische1 (ISO-8859-1) Zeichen enthalten, werden standardmäßig als latin1 ausgegeben, obwohl sie mehr oder weniger in utf8 gespeichert sind. Auf diese Weise funktionieren Skripte aus einer Zeit vor dem Unicode auch mit einem Unicode-fähigen Perl gleich.
Mirod
3
Mit dem Pragma utf8 können Sie Ihre Quelle nicht in UNICODE schreiben. Es erzwingt das Verständnis Ihrer Quelle in der UTF-8- (oder UTF-EBCDIC-) Codierung von UNICODE, eine wichtige Unterscheidung.
Chas. Owens
83

Sie können das offene Pragma verwenden .

Zum Beispiel. unten werden STDOUT, STDIN & STDERR für die Verwendung von UTF-8 festgelegt ....

use open qw/:std :utf8/;
draegtun
quelle
1
Übrigens ... ich habe dir +1 gegeben. Ich denke, binmode (STDOUT, ': utf8') ist in dieser Situation wahrscheinlich korrekter. "use open" hat andere gute Verwendungszwecke, aber ich kann anscheinend nicht herausfinden, wie Sie es so einstellen können, dass nur STDOUT codiert wird.
Draegtun
66

TMTOWTDI , wählen Sie die Methode, die am besten zu Ihrer Arbeitsweise passt. Ich verwende die Umgebungsmethode, damit ich nicht darüber nachdenken muss.

In der Umwelt :

export PERL_UNICODE=SDL

in der Kommandozeile :

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

oder mit binmode :

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

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

oder mit dem offenen Pragma :

use open ":encoding(utf8)";
use open IN => ":encoding(utf8)", OUT => ":utf8";
Chas. Owens
quelle
1
+1 für eine umfassende Antwort; Beachten Sie, dass dies SDLsowohl mit -Cals auch impliziert ist PERL_UNICODE. use open ':locale'Erwähnenswert ist auch das Pragma, da es das In-Script-Äquivalent von -Cund ist export PER_UNICODE=. Mit jeder dieser drei Optionen erhalten Sie UTF8-Unterstützung für alle Eingabe- und Ausgabestreams (ob Dateien oder stdin / stdout / stderr), vorausgesetzt, das Gebietsschema Ihrer Umgebung basiert auf UTF8. Schließlich auch treat Quelle Code als UTF8, verwenden Sie die use utf8;Pragma.
mklement0
perl -Mutf8 -CSDL -e '...'Ermöglicht das Konsumieren / Ausgeben von UTF-8 sowie das Verwenden von UTF-8-Literalen im Inneren, -ez. B. für den perl -Mutf8 -CASDL -pe 'y/āáǎàēéěèīíǐìōóǒòūúǔùǖǘǚǜĀÁǍÀĒÉĚÈĪÍǏÌŌÓǑÒŪÚǓÙǕǗǙǛ/aaaaeeeeiiiioooouuuuüüüüAAAAEEEEIIIIOOOOUUUUÜÜÜÜ/'
Fallordner
0

Danke, endlich eine Lösung, um utf8 :: encode nicht über den gesamten Code zu setzen. Zum Synthetisieren und Vervollständigen für andere Fälle, wie das Schreiben und Lesen von Dateien in utf8, und funktioniert auch mit LoadFile einer YAML-Datei in 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}." ";

wo cache.yaml ist:

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

Mach in deiner Shell: $ env | grep LANG

Dies wird wahrscheinlich zeigen, dass Ihre Shell kein utf-8-Gebietsschema verwendet.

nxadm
quelle
Eigentlich wurde es auf utf-8 gesetzt. Das Problem war, dass ich in STDOUT ausgegeben habe, ohne binmode auf utf-8 zu setzen;
2
Dies wäre ein orthogonales Problem. Sie benötigen Ihr Perl-Skript, um korrekte Daten auszugeben, bevor Sie sich Gedanken darüber machen können, wie Ihr Terminalemulator sie interpretiert.
Jrockway