Wie werden Perl-Strings intern dargestellt? Welche Codierung wird verwendet? Wie gehe ich mit verschiedenen Kodierungen richtig um?
Ich benutze Perl schon ziemlich lange, aber es enthielt nicht viel String-Handling in verschiedenen Codierungen, und als ich auf ein kleines Problem stieß, das etwas mit Codierungen zu tun hatte, griff ich normalerweise auf etwas Schamanisches zurück Aktionen.
Bis zu diesem Moment dachte ich über Perl-Strings als Byte-Sequenzen nach, was ziemlich gut zu meinen Aufgaben passte. Jetzt muss ich etwas Verarbeitung von UTF-8-codierten Datei und hier beginnt Probleme.
Zuerst lese ich die Datei in eine Zeichenfolge wie folgt:
%Vor%dann einfach ausdrucken:
%Vor% Und ich bekomme zwei Dinge: eine Warnung Wide character in print at <scriptname> line <n>
und einen Müll in der Konsole. Also kann ich schlussfolgern, dass Perl-Strings ein Konzept von "Charakter" haben, das "breit" sein kann oder nicht, aber beim Ausdruck werden diese "Wide" -Zeichen in der Konsole als mehrere Bytes dargestellt, nicht als einzelnes "Zeichen".
(Ich frage mich jetzt, warum all meine früheren Erfahrungen mit Binärdateien so funktionierten, wie ich es erwartet hatte, ohne irgendwelche "Zeichen" -Ausgaben zu funktionieren.)
Warum sehe ich Müll in der Konsole? Wenn Perl Zeichenfolgen in einer bekannten Codierung speichert, glaube ich nicht, dass es ein großes Problem ist, die Konsolencodierung zu finden und Text richtig zu drucken. (Ich benutze Windows, BTW).
Wenn Perl Zeichenfolgen als Zeichenfolgen mit variabler Breite speichert (z. B. mit der gleichen UTF-8-Codierung), warum wird dies so gemacht? Aus meiner C-Erfahrung Umgang mit Zeichenfolgen ist PAIN.
Aktualisieren .
Ich benutze zwei Computer zum Testen, einer läuft Windows 7 x64 mit installiertem englischem Sprachpaket, aber mit russischen Ländereinstellungen (so habe ich cp866 als OEM-Codepage und cp1251 als ANSI) mit ActivePerl 5.10.1 x64; Ein anderes Programm führt Windows XP 32 Bit Russisch mit Cygwin Perl 5.10.0 aus.
Dank der Links habe ich jetzt viel fundierteres Verständnis darüber, was vor sich geht und wie die Dinge gemacht werden sollten.
Wenn utf8 vor dem Lesen aus der Datei gesetzt wird, dekodiert es automatisch die Bytes in die interne Kodierung. (Dies ist auch UTF-8, aber Sie müssen nicht wissen, und sollte nicht darauf angewiesen.)
Vor dem Drucken müssen Sie die Zeichen zurück in Bytes codieren.
%Vor%Es gibt auch eine Zwei-Argument-Form von encode für andere Kodierungen als Unicode. (Dieser Satz hallt zu sehr wider, nicht wahr?)
Hier ist eine gute Referenz. (Wäre mehr gewesen, aber es ist mein erster Beitrag.) Schauen Sie sich auch perlunutut und den Unicode-Artikel über Joel auf Software an.
Oh, und es muss Multi-Byte-Strings verwenden, weil es sonst einfach nicht Unicode ist.
Perl-Zeichenfolgen werden intern in einer von zwei Codierungen gespeichert, entweder einer 8-Bit-Byte-orientierten nativen Codierung oder UTF-8. Für die Rückwärtsvergleichbarkeit wird vorausgesetzt, dass alle I / O und Strings in nativer Codierung sind, sofern nicht anders angegeben. Die native Codierung ist normalerweise 8-Bit-ASCII, aber dies kann mit use locale
geändert werden.
In Ihrem Beispiel rufen Sie binmode auf Ihrem Eingabe-Handle auf, um es zu ändern, um :utf8
Semantik zu verwenden. Ein Effekt davon ist, dass alle Strings, die von diesem Handle gelesen werden, als UTF-8 codiert werden. print
schreibt standardmäßig nach STDOUT
, und STDOUT
erwartet standardmäßig native codierte Zeichen.
Wenn Perl versucht, das Richtige zu tun, kann eine UTF-8-Zeichenfolge an eine native codierte Ausgabe gesendet werden. Wenn dem Handle jedoch keine Codierung zugeordnet ist, muss er erraten, wie Multibyte-Zeichen ausgegeben werden und es wird fast sicher falsch geraten. Das bedeutet, dass die Warnung bedeutet, dass ein Multi-Byte-Zeichen an einen Stream gesendet wurde, der nur Single-Byte-Zeichen erwartet und das Ergebnis war, dass das Zeichen wahrscheinlich bei der Übersetzung beschädigt wurde.
Je nachdem, was Sie erreichen möchten, können Sie das von dylan erwähnte Encodemodul verwenden, um die UTF-8-Daten in einen einzelnen Byte-Zeichensatz zu konvertieren, der sicher gedruckt werden kann oder wenn Sie wissen, was mit STDOUT
verbunden ist Handle UTF-8 Sie können binmode(STDOUT, ':utf8');
verwenden, um Perl mitzuteilen, dass Daten, die an STDOUT
gesendet werden, als UTF-8 gesendet werden sollen.
Sie sollten Ihre tatsächlichen Windows- und Perl-Versionen erwähnen, da dies von Ihren verwendeten Versionen und installierten Sprachpaketen abhängt.
Ansonsten schau dir zuerst das PerlUnicode Handbuch an -
Perl verwendet logisch breite Zeichen, um Zeichenfolgen intern darzustellen.
Es wird Ihre Aussagen bestätigen.
Windows installiert nicht alle UTF8-Zeichen vollständig - dies könnte der Grund für Ihr Problem sein. Möglicherweise müssen Sie ein zusätzliches Sprachpaket installieren.