ich habe ein Problem, das vermutlich mal wieder mit Encoding
zusammenhängt. Ausgangslage ist mein Wunsch, eine Zeichenkette in
einzelne Zeichen zu zerlegen. Das mache ich wie folgt:
#!/usr/bin/perl
use strict;
use warnings;
my $string='!"§$%';
print "$_\n" for split(//, $string);
print '-' x 10,"\n";
print "$1\n" while $string =~ /(.)/g;
Putzigerweise wird das Paragraphenzeichen in zwei einzelne Zeichen
zerlegt. Dies ist die Ausgabe:
!
"
�
�
$
%
----------
!
"
�
�
$
%
Die lustigen Zeichen da oben sind C2 und A7.
Gesehen habe ich dieses Verhalten unter 5.8.8. Mich beschleicht das
Gefühl, dass da irgendwo ein Encoding den Bach runter geht. Aber wo? Und
warum? :-)
Wenn ich in obigem Programm das Pragma utf8 verwende, dann wird das
Paragraphenzeichen nur noch als ein Zeichen ausgegeben, jedoch auch
falsch: A7. Im Programm selbst ist das Paragraphenzeichen als C2A7
codiert (sagt mir zumindest 'od', wenn ich den Quelltext damit ausgebe).
Wo zwischen diesen schlichten Zeilen liegt der Fehler? Und: Wie kommt
man denn nun an einzelne Zeichen einer Zeichenkette heran? Geht das mit
pack und 'U'?
Vielen Dank für die Erleuchtung,
Gregor
--
Dipl.-Inform. Gregor Goldbach (PKI Team)
Phone: +49 40 808077-621 Fax: +49 40 808077-556 Mail:gold...@dfn-cert.de
DFN-CERT Services GmbH, https://www.dfn-cert.de, Phone +49 40 808077-555
Sitz / Register: Hamburg, AG Hamburg, HRB 88805, Ust-IdNr.: DE 232129737
Sachsenstraße 5, 20097 Hamburg/Germany, CEO: Dr. Klaus-Peter Kossakowski
DFN-PKI
https://www.pki.dfn.de/
Die Zeichen sind U+FFFD, und die malt Dein Terminal hin, weil es mit den
einzelnen Bytes C2 und A7 nichts anfangen kann.
> Gesehen habe ich dieses Verhalten unter 5.8.8. Mich beschleicht das
> Gefühl, dass da irgendwo ein Encoding den Bach runter geht. Aber wo? Und
> warum? :-)
Ich rate mal, dass Dein Script in UTF-8 kodiert ist. Der Perl-Compiler
rät nicht, dem musst Du das sagen.
> Wenn ich in obigem Programm das Pragma utf8 verwende,
Genau so. Damit sagst Du dem Compiler: Dieser Source-Code ist in UTF-8
geschrieben. Das ist (etwas vereinfacht) der einzige Effekt, den das das
Pragma hat.
> dann wird das
> Paragraphenzeichen nur noch als ein Zeichen ausgegeben, jedoch auch
> falsch: A7.
Das ist im Prinzip korrekt. Das Paragraphenzeichen hat den Code U+00A7.
Aber ...
Du willst, dass die Ausgabe in UTF-8 erfolgt. Auch das musst Du Perl
wiederum sagen (es könnte ja sein, dass Du irgendwelche binären Daten
ausgeben willst ...). Dazu dient binmode:
binmode STDOUT, ":encoding(UTF-8)";
Damit wird das Zeichen "\x{A7}" als in die beiden Bytes 0xC2 0xA7
umgewandelt, das Zeichen "\x{20AC}" in die drei Bytes 0xE2 0x82 0xAC
und so weiter.
Grundregel: Wenn Du Byteströme als Zeichenfolgen lesen willst, musst Du
sie dekodieren, wenn Du Zeichenfolgen als Byteströme schreiben willst,
musst Du sie kodieren.
Es gibt einige Automatismen, die Dir einen Teil der Arbeit abnehmen,
aber die haben auch alle ihre Tücken:
* use encoding('UTF-8'): Das DWIM-Modul: Verwendet UTF-8 für das Script
selbst, einige Filehandles (z.B. STDIN, STDOUT, aber nicht STDERR)
und noch ein paar andere Sachen. Gut gemeint aber nicht gut, DWIM
steht hier für "Does what it wants" nicht "Do what I mean" ;-).
* Die Commandline-Option -C: Leider in 5.10.x nicht mehr im Shebang
supported, daher nur mehr für Einzeiler brauchbar.
* Die Environmentvariable PERL5_UNICODE: Ist nett für eigene Scripts,
aber Du kannst mit hoher Wahrscheinlichkeit davon ausgehen, dass
Scripts anderer Leute nicht mehr funktionieren, wenn das gesetzt ist.
> Im Programm selbst ist das Paragraphenzeichen als C2A7
> codiert (sagt mir zumindest 'od', wenn ich den Quelltext damit ausgebe).
Bitte schreib zwei Bytes als «C2 A7», «0xC2 0xA7» oder «"\x{C2}\x{A7}"».
Wenn Du das zusammenpappst, weiß man nicht, ob Du zwei Bytes oder ein
einziges Zeichen mit dem Code C2A7 meinst.
hp
vorweg erst einmal ein großes „Danke!“ für die ausführliche Antwort!
[nicht-ASCII-Zeichen in Zeichenkette]
>> Wenn ich in obigem Programm das Pragma utf8 verwende,
>
> Genau so. Damit sagst Du dem Compiler: Dieser Source-Code ist in UTF-8
> geschrieben. Das ist (etwas vereinfacht) der einzige Effekt, den das das
> Pragma hat.
In meinem Hinterkopf schlummert noch der Eindruck, das man das
eigentlich nicht nehmen möchte, sondern bei Bedarf die Zeichenketten mit
encode() und decode() hin- und herkonvertiert.
Dieser Eindruck hat sich vor Jahren eingeprägt, weil die Automatismen,
die Du unten erwähnst, alle nur halbe Sachen machen und der geneigte
Programmierer doch wieder verraten und verkauft ist, wenn er oder sie
sich nicht selbst darum kümmert. Ist der Eindruck richtig? Falls nein:
Wie machst Du das so? ;-)
Insbesondere gibt es ja diese mysteriöse UTF-8-Flagge, die Perl-Code
gerne mal hisst und wieder einholt — scheinbar nach Belieben. Hat sich
das Verhalten eigentlich bei neueren Perlen (endlich) mal gesetzt oder
muss man da immer noch aufpassen wie ein Fuchs?
Sonnige Grüße vom Rande des Encoding-Wahns,
"use utf8" ist völlig OK, "use encoding..." ist es, von dem man
besser die Finger lässt.
> Dieser Eindruck hat sich vor Jahren eingeprägt, weil die Automatismen,
> die Du unten erwähnst, alle nur halbe Sachen machen und der geneigte
> Programmierer doch wieder verraten und verkauft ist, wenn er oder sie
> sich nicht selbst darum kümmert.[...]
"use utf8" schützt nicht davor, sich mit Daten in anderen Encodings
zu infizieren :)
Dass man wirklich seinem Perl ganz genau sagen muss in welchem
Encoding man das Script schreibt, aus Handles liest und in solche
schreibt wird sich auch in absehbarer Zeit nicht verhindern lassen, das
liegt ja in der Natur von UTF8 selbst. Wenn Daten ohne BOM hereinkommen
dann kann Perl nicht wissen woran es ist.
> Insbesondere gibt es ja diese mysteriöse UTF-8-Flagge, die Perl-Code
> gerne mal hisst und wieder einholt — scheinbar nach Belieben. Hat sich
> das Verhalten eigentlich bei neueren Perlen (endlich) mal gesetzt oder
> muss man da immer noch aufpassen wie ein Fuchs?
Das ist überwiegend konsistent. Die meisten Probleme auf dieser Ebene
macht ja nicht Perl selbst, sondern sie werden durch den Datenfluss
durch Module produziert (z.B. DBD::*). Und oft genug ist das was man
sieht eigentlich richtig und die Fehlerquelle das Terminal (oder
die Zeichensatzdeklaration im HTTP-Header, oder der Font im GUI...).
-Christian
Das eine hat mit dem anderen nichts zu tun: "use utf8" bezieht sich auf
den Source-Code. Das verwendest Du dann, wenn Nicht-ASCII-Zeichen in
deinem Source-Code (in String-Konstanten, im POD oder vielleicht sogar
in Variablennamen) vorkommen und das Source-File in UTF-8 kodiert ist.
Zur Laufzeit hat das dann keinen Einfluss mehr.
encode und decode hingegen sind Funktionen, die zur Laufzeit aufgerufen
werden. Die verwendest Du, um Zeichenketten als Bytestrings zu kodieren
bzw. Bytestrings zu Zeichenketten zu dekodieren, üblicherweise deswegen,
weil die Kommunikation mit der Außenwelt über Bytes erfolgt. (Statt
encode/decode direkt zu verwenden, kann man oft spezifischere
Mechanismen verwenden - bei Files z.B. die Perl I/O Layer).
> Dieser Eindruck hat sich vor Jahren eingeprägt, weil die Automatismen,
> die Du unten erwähnst, alle nur halbe Sachen machen und der geneigte
> Programmierer doch wieder verraten und verkauft ist, wenn er oder sie
> sich nicht selbst darum kümmert. Ist der Eindruck richtig? Falls nein:
> Wie machst Du das so? ;-)
Ich überlege mir, ob das, womit ich da arbeite, Bytestrings oder
Characterstrings sind. Wenn es semantisch Characterstrings sein sollten
aber auf Grund der Interface-Spezifikation Bytestrings sind (typisches
Beispiel: Texte, die aus Files eingelesen werden), dann wandle ich so
früh wie möglich nach dem Einlesen bzw. so spät wie möglich vor dem
Rausschreiben um. Sehr oft kann das der I/O-Mechanismus (PerlIO, DBD,
etc) dann ist das nur ein weiterer Parameter beim open/connect/etc.,
sonst muss man halt mit decode/encode arbeiten.
> Insbesondere gibt es ja diese mysteriöse UTF-8-Flagge, die Perl-Code
> gerne mal hisst und wieder einholt — scheinbar nach Belieben.
Ist ist überhaupt nicht mysteriös, nur falsch benannt. Perl
unterscheidet (jedenfalls in 5.8 und 5.10, in 5.12 könnte es wieder
anders werden) zwischen "character strings" und "byte strings".
Die unterscheiden sich leicht in der Semantik (z.B. ist "\x{C4}" =~ /\w/
true, wenn es ein Character-String ist (da U+00C4 = LATIN CAPITAL LETTER
A WITH DIAERESIS) aber false, wenn es ein Bytestring ist (da ist ein
einfach nur ein Byte ohne Zuordnung zu einem Zeichen)) und die beiden
Arten von Strings werden durch dieses Flag unterschieden. Der Name des
Flags leitet sich davon ab, dass Character-Strings intern UTF-8-kodiert
sind, aber das ist für ein Perl-Programm an sich gar nicht festzustellen
("ä" hat die Länge 1, nicht 2, wie das bei UTF-8 sein müsste).
> Hat sich das Verhalten eigentlich bei neueren Perlen (endlich) mal
> gesetzt oder muss man da immer noch aufpassen wie ein Fuchs?
Das funktioniert seit 5.8.1 ziemlich konsistent (in 5.8.0 gab es noch
ein paar gröbere Bugs, wenn ich mich recht erinnere). Das Hauptproblem
war (und ist), dass die Dokumentation sehr verwirrend ist und daher
viele Perl-Programmierer (leider auch viele Autoren von CPAN-Modulen)
das Konzept nicht verstanden haben. Eine große Verbesserung war in dem
Zusammenhang meiner Meinung nach perldoc perlunitut von Juerd Waalboer.
hp
Zu unerw�nschten Nebenwirkungen befragen Sie Ihren Arzt oder Apotheker
oder lesen Sie den Beipackzettel (perldoc encoding).
Ich rate von "use encoding 'WHATEVER';" ab - das macht f�r meinen
Geschmack zu viele Dinge gleichzeitig, die IMHO voneinander unabh�ngig
sein sollten.
Empfehlenswert sind IMHO zwei Varianten:
* Das Script ist in UTF-8 kodiert und mit "use utf8;" gekennzeichnet.
* Das Script ist in US-ASCII kodiert.
hp
> "use utf8" schützt nicht davor, sich mit Daten in anderen Encodings
> zu infizieren :)
;-)
> Dass man wirklich seinem Perl ganz genau sagen muss in welchem
> Encoding man das Script schreibt, aus Handles liest und in solche
> schreibt wird sich auch in absehbarer Zeit nicht verhindern lassen, das
> liegt ja in der Natur von UTF8 selbst. Wenn Daten ohne BOM hereinkommen
> dann kann Perl nicht wissen woran es ist.
Kommt perl denn mit BOM klar? Und wenn ja: ab welcher Version? ;-)
Wo kann ich das zur Not nachlesen?
>> Insbesondere gibt es ja diese mysteriöse UTF-8-Flagge, die Perl-Code
>> gerne mal hisst und wieder einholt — scheinbar nach Belieben. Hat sich
>> das Verhalten eigentlich bei neueren Perlen (endlich) mal gesetzt oder
>> muss man da immer noch aufpassen wie ein Fuchs?
>
> Das ist überwiegend konsistent. Die meisten Probleme auf dieser Ebene
> macht ja nicht Perl selbst, sondern sie werden durch den Datenfluss
> durch Module produziert (z.B. DBD::*). Und oft genug ist das was man
Was können die Module denn flacsh machen? Gibt es da eine schwarze Liste
von Dingen, die nicht getan werden sollten? Ich vermute, es steht mal
wieder zwischen den über mehrere Hilfsseiten verstreuten Zeilen...
> sieht eigentlich richtig und die Fehlerquelle das Terminal (oder
> die Zeichensatzdeklaration im HTTP-Header, oder der Font im GUI...).
Hm... ich erinnere mich dunkel an irgendwelche XS-Eingeweide, deren
Funktionen mal mit UTF-8 klarkommen, und mal nicht. Wenn ein Modul dabei
ist, dass da nicht sauber arbeitet, geht wohl auch alles kaputt.
Will ich dann eigentlich utf8::is_utf8 in meine Testsuite aufnehmen?
> Das eine hat mit dem anderen nichts zu tun: "use utf8" bezieht sich auf
> den Source-Code. Das verwendest Du dann, wenn Nicht-ASCII-Zeichen in
> deinem Source-Code (in String-Konstanten, im POD oder vielleicht sogar
> in Variablennamen) vorkommen und das Source-File in UTF-8 kodiert ist.
> Zur Laufzeit hat das dann keinen Einfluss mehr.
Ah! So hatte ich das Pragma noch gar nicht verstanden. Danke.
Aber ich mache mir gerade Sorgen. Die Dokumentation von utf8 sagt (5.8.8.):
Note that if you have bytes with the eighth bit on in your script
(for
example embedded Latin-1 in your string literals), "use utf8" will be
unhappy since the bytes are most probably not well-formed UTF-8. If
you want to have such bytes and use utf8, you can disable utf8 until
the end the block (or file, if at top level) by "no utf8;".
Bei lokalisierten Meldungen, die ja gerne mal Umlaute enthalten, muss an
dann wohl doch wieder auf decode/encode zurückgreifen, richtig?
>> Wie machst Du das so? ;-)
>
> Ich überlege mir, ob das, womit ich da arbeite, Bytestrings oder
> Characterstrings sind. Wenn es semantisch Characterstrings sein sollten
> aber auf Grund der Interface-Spezifikation Bytestrings sind (typisches
> Beispiel: Texte, die aus Files eingelesen werden), dann wandle ich so
> früh wie möglich nach dem Einlesen bzw. so spät wie möglich vor dem
> Rausschreiben um. Sehr oft kann das der I/O-Mechanismus (PerlIO, DBD,
> etc) dann ist das nur ein weiterer Parameter beim open/connect/etc.,
> sonst muss man halt mit decode/encode arbeiten.
Wenn ich also weiß, dass die Ein- und Ausgabe stets in ISO 8859-1
codiert werden soll, reicht ein schlichtes
binmode(STDIN, ':encoding(latin1)');
binmode(STDOUT, ':encoding(latin1)');
am Anfang, richtig?
>> Insbesondere gibt es ja diese mysteriöse UTF-8-Flagge, die Perl-Code
>> gerne mal hisst und wieder einholt — scheinbar nach Belieben.
>
> Ist ist überhaupt nicht mysteriös, nur falsch benannt. Perl
Bisher für mich schon ;)
[Erhellende Erläuterung entfernt]
> Arten von Strings werden durch dieses Flag unterschieden. Der Name des
> Flags leitet sich davon ab, dass Character-Strings intern UTF-8-kodiert
> sind, aber das ist für ein Perl-Programm an sich gar nicht festzustellen
> ("ä" hat die Länge 1, nicht 2, wie das bei UTF-8 sein müsste).
Auch nicht mit utf8::valid?
>> Hat sich das Verhalten eigentlich bei neueren Perlen (endlich) mal
>> gesetzt oder muss man da immer noch aufpassen wie ein Fuchs?
>
> Das funktioniert seit 5.8.1 ziemlich konsistent (in 5.8.0 gab es noch
> ein paar gröbere Bugs, wenn ich mich recht erinnere). Das Hauptproblem
> war (und ist), dass die Dokumentation sehr verwirrend ist und daher
In der Tat. Ich habe während des Schreibens dieser Antwort mal ein wenig
in PerlIO, perunicode, perlrun, perliol, perluniintro und Konsorten
gelesen. Das ist wirklich nicht schön erklärt...
> viele Perl-Programmierer (leider auch viele Autoren von CPAN-Modulen)
> das Konzept nicht verstanden haben. Eine große Verbesserung war in dem
> Zusammenhang meiner Meinung nach perldoc perlunitut von Juerd Waalboer.
Vielleicht schrieb er das ja nach folgender Diskussion:
http://www.nntp.perl.org/group/perl.perl5.porters/2007/04/msg123599.html
:-)
Danke für Deine Erläuterungen! Die haben wirklich ein bisschen Licht ins
Dunkel gebracht. Wie schnell das doch wieder geht. Eigentlich wollte ich
doch an *Zeichen* einer Zeichenkette herankommen. ;)
Nein, Du musst Dich nur an das halten, was Du Perl versprochen hast:
Wenn Du "use utf8;" verwendest, muss das Script in UTF-8 kodiert sein,
und nicht in Latin-1 oder KOI-8 oder sonstwas. Unter Linux ist
heutzutage die Locale meistens UTF-8, wenn Du das Script dort mit einem
Texteditor schreibst, ist das also meistens der Fall. Unter Windows ist
das eine Einstellung am Editor (wenn der Editor es kann).
>>> Wie machst Du das so? ;-)
>>
>> Ich �berlege mir, ob das, womit ich da arbeite, Bytestrings oder
>> Characterstrings sind. Wenn es semantisch Characterstrings sein sollten
>> aber auf Grund der Interface-Spezifikation Bytestrings sind (typisches
>> Beispiel: Texte, die aus Files eingelesen werden), dann wandle ich so
>> fr�h wie m�glich nach dem Einlesen bzw. so sp�t wie m�glich vor dem
>> Rausschreiben um. Sehr oft kann das der I/O-Mechanismus (PerlIO, DBD,
>> etc) dann ist das nur ein weiterer Parameter beim open/connect/etc.,
>> sonst muss man halt mit decode/encode arbeiten.
>
> Wenn ich also wei�, dass die Ein- und Ausgabe stets in ISO 8859-1
> codiert werden soll, reicht ein schlichtes
>
> binmode(STDIN, ':encoding(latin1)');
> binmode(STDOUT, ':encoding(latin1)');
>
> am Anfang, richtig?
Ja.
>> Arten von Strings werden durch dieses Flag unterschieden. Der Name des
>> Flags leitet sich davon ab, dass Character-Strings intern UTF-8-kodiert
>> sind, aber das ist f�r ein Perl-Programm an sich gar nicht festzustellen
>> ("�" hat die L�nge 1, nicht 2, wie das bei UTF-8 sein m�sste).
>
> Auch nicht mit utf8::valid?
Nein. utf8::valid liefert f�r jeden konsistenten String true zur�ck,
�ber die interne Interpretation sagt es nichts aus. (Es gibt in Perl
Funktionen, die auf Interna zugreifen k�nnen, aber das sehe ich nicht
als normalen Gebrauch).
F�r Perl-Code ist das v�llig egal, wie diese Strings intern
abgespeichert sind - man k�nnte jedes Zeichen als 32-bit-Wert
abspeichern und korrekte Perl-Programme k�nnten den Unterschied nicht
feststellen. Nur XS-Code m�sste ge�ndert werden, weil der ja
(notwendigerweise) auf die interne Representation zugreift.
>> Eine gro�e Verbesserung war in dem Zusammenhang meiner Meinung nach
>> perldoc perlunitut von Juerd Waalboer.
>
> Vielleicht schrieb er das ja nach folgender Diskussion:
>
> http://www.nntp.perl.org/group/perl.perl5.porters/2007/04/msg123599.html
Nein, das ist schon �lter. Ich glaube ich habe 2003 mit Juerd dar�ber
geplaudert (ich wollte damals selbst sowas schreiben aber Juerd ist mir
zuvorgekommen).
hp
Ab Version 6.
> Wo kann ich das zur Not nachlesen?
http://perlcabal.org/syn/S32/IO.html#IO
Grüße,
Moritz
--
Moritz Lenz
http://perl-6.de/ http://moritz.faui2k3.org/
>>> Dass man wirklich seinem Perl ganz genau sagen muss in welchem
>>> Encoding man das Script schreibt, aus Handles liest und in solche
>>> schreibt wird sich auch in absehbarer Zeit nicht verhindern lassen, das
>>> liegt ja in der Natur von UTF8 selbst. Wenn Daten ohne BOM hereinkommen
>>> dann kann Perl nicht wissen woran es ist.
>> Kommt perl denn mit BOM klar? Und wenn ja: ab welcher Version? ;-)
>
> Ab Version 6.
Und bei Perl 5?
>> Bei lokalisierten Meldungen, die ja gerne mal Umlaute enthalten, muss an
>> dann wohl doch wieder auf decode/encode zur�ckgreifen, richtig?
>
> Nein, Du musst Dich nur an das halten, was Du Perl versprochen hast:
> Wenn Du "use utf8;" verwendest, muss das Script in UTF-8 kodiert sein,
> und nicht in Latin-1 oder KOI-8 oder sonstwas. Unter Linux ist
> heutzutage die Locale meistens UTF-8, wenn Du das Script dort mit einem
> Texteditor schreibst, ist das also meistens der Fall.
Neue Programme schreibe ich in UTF-8. Altlasten habe ich mit recode
umcodiert, da sollte also alles gut sein.
>>>> Wie machst Du das so? ;-)
[...]
>>> Sehr oft kann das der I/O-Mechanismus (PerlIO, DBD,
>>> etc) dann ist das nur ein weiterer Parameter beim open/connect/etc.,
>>> sonst muss man halt mit decode/encode arbeiten.
>> Wenn ich also wei�, dass die Ein- und Ausgabe stets in ISO 8859-1
>> codiert werden soll, reicht ein schlichtes
>>
>> binmode(STDIN, ':encoding(latin1)');
>> binmode(STDOUT, ':encoding(latin1)');
>>
>> am Anfang, richtig?
>
> Ja.
Wundervoll ;)
>>> Arten von Strings werden durch dieses Flag unterschieden. Der Name des
>>> Flags leitet sich davon ab, dass Character-Strings intern UTF-8-kodiert
>>> sind, aber das ist f�r ein Perl-Programm an sich gar nicht festzustellen
>>> ("�" hat die L�nge 1, nicht 2, wie das bei UTF-8 sein m�sste).
>> Auch nicht mit utf8::valid?
>
> Nein. utf8::valid liefert f�r jeden konsistenten String true zur�ck,
> �ber die interne Interpretation sagt es nichts aus.
W�rde ich denn utf8:valid verwenden k�nnen, um zu entdecken, ob sich ein
latin1-codierter Umlaut in einer Zeichenkette verbirgt, die UTF-8 sein
sollte?
Ich denke jetzt gerade an eine Art und Weise, wie ich in Tests
feststellen kann, ob Daten noch konsistent codiert sind. Folgendes
Gedankenexperiment:
- Formulare im Webbrowser nehmen KOI-8 an
- Perl-Programm empf�ngt Daten und schreibt sie in eine Datenbank, die
UTF-8 haben will
- Daten werden wieder ausgelesen und KOI-8-codiert weitergereicht
Gibt es eine Funktion, mit der ich pr�fen kann, ob Perl denkt, dass eine
Zeichenkette konsistent codiert ist?
--
Dipl.-Inform. Gregor Goldbach (PKI Team)
Phone: +49 40 808077-621 Fax: +49 40 808077-556 Mail:gold...@dfn-cert.de
DFN-CERT Services GmbH, https://www.dfn-cert.de, Phone +49 40 808077-555
Sitz / Register: Hamburg, AG Hamburg, HRB 88805, Ust-IdNr.: DE 232129737
Sachsenstra�e 5, 20097 Hamburg/Germany, CEO: Dr. Klaus-Peter Kossakowski
DFN-PKI
https://www.pki.dfn.de/
Kommt darauf an, wovon Du redest: Wenn Du von der internen
UTF-8-Kodierung von Character-Strings redest (die Dich eigentlich als
Perl-Programmierer nichts angeht), dann ja. Aber Du stierlst hier in den
Eingeweiden von Perl herum, und wenn Du das bei "normaler"
Programmiert�tigkeit tust, dann hast Du irgendwas prinzipiell falsch
gemacht. Es gibt nur zwei Gr�nde, das zu tun:
1) Du willst wissen, wie die Version des Perl-Interpreters, die Du
gerade verwendest, funktioniert (in der n�chsten kann es schon wieder
anders sein)
2) Du suchst einen Bug.
Wenn Du von Byte-Strings redest, die UTF-8-kodiert sein sollten, dann
kannst Du utf8::valid nicht verwenden, denn die sind immer valide.
Um zu �berpr�fen, ob ein Byte-String UTF-8-kodiert ist, verwende
decode() mit einem passenden Check-Argument.
> Ich denke jetzt gerade an eine Art und Weise, wie ich in Tests
> feststellen kann, ob Daten noch konsistent codiert sind. Folgendes
> Gedankenexperiment:
>
> - Formulare im Webbrowser nehmen KOI-8 an
> - Perl-Programm empf�ngt Daten und schreibt sie in eine Datenbank, die
> UTF-8 haben will
> - Daten werden wieder ausgelesen und KOI-8-codiert weitergereicht
Theoretisch sollte man
1) Daten in KOI-8 schon gar nicht in eine Datenbank schreiben k�nnen,
die UTF-8 haben will,
2) Nicht-UTF-8-Daten nicht als Character-String lesen k�nnen.
In der Praxis kann es aber nat�rlich sein, dass an beiden Stellen die
entsprechenden Checks fehlen (sei es, weil niemand daran gedacht hat,
sie zu implementieren, oder sei es, weil sie absichtlich (meistens mit
der Begr�ndung "zu langsam") weggelassen wurde). Dann hat Perl unter
Umst�nden tats�chlich einen String, der nicht korrekt kodiert ist.
> Gibt es eine Funktion, mit der ich pr�fen kann, ob Perl denkt, dass eine
> Zeichenkette konsistent codiert ist?
Ja, utf8::valid.
hp
Was meinst Du mit "kommt Perl mit BOM klar?"
Bei Encoding UTF-16 schreibt Perl am Fileanfang ein BOM und
interpretiert es beim Einlesen richtig.
In UTF-8 wird ein BOM am Fileanfang nicht ignoriert sondern als ZERO
WIDTH NO-BREAK SPACE gelesen.
Ist das das, was Du erwartest?
>>> Insbesondere gibt es ja diese mysteriöse UTF-8-Flagge, die Perl-Code
>>> gerne mal hisst und wieder einholt — scheinbar nach Belieben. Hat sich
>>> das Verhalten eigentlich bei neueren Perlen (endlich) mal gesetzt oder
>>> muss man da immer noch aufpassen wie ein Fuchs?
>>
>> Das ist überwiegend konsistent. Die meisten Probleme auf dieser Ebene
>> macht ja nicht Perl selbst, sondern sie werden durch den Datenfluss
>> durch Module produziert (z.B. DBD::*). Und oft genug ist das was man
>
> Was können die Module denn flacsh machen?
Die Anzahl der möglichen Fehler ist unendlich :-(.
Zu den beliebtesten Fehlern zählen:
* Verwechslungen von Byte- und Characterstrings, d.h., es wird das eine
zurückgeliefert, obwohl es semantisch das andere sein sollte.
* Herummurksen mit internen Funktionen wie _utf8_on/_utf8_off,
ohne verstanden zu haben, was die tun.
* Übergabe von Perl-Strings an bzw. von C-Library-Funktionen ohne
korrekte Kodierung bzw. Dekodierung.
* Das gleiche mit File-I/O.
>> sieht eigentlich richtig und die Fehlerquelle das Terminal (oder
>> die Zeichensatzdeklaration im HTTP-Header, oder der Font im GUI...).
>
> Hm... ich erinnere mich dunkel an irgendwelche XS-Eingeweide, deren
> Funktionen mal mit UTF-8 klarkommen, und mal nicht. Wenn ein Modul dabei
> ist, dass da nicht sauber arbeitet, geht wohl auch alles kaputt.
> Will ich dann eigentlich utf8::is_utf8 in meine Testsuite aufnehmen?
Kommt darauf an, was Du damit testen willst. Diese Funktion testet, ob
der String ein Characterstring (im Gegensatz zum Bytestring) ist. Lass
Dich nicht vom Namen verwirren!
hp
>> Kommt perl denn mit BOM klar?
>
> Was meinst Du mit "kommt Perl mit BOM klar?"
Mit der Frage wollte ich wissen, ob perl (das Programm) so markierte
Dateien richtig verarbeiten kann. Aus Deiner Antwort schließe ich, dass
dem so ist.
> Bei Encoding UTF-16 schreibt Perl am Fileanfang ein BOM und
> interpretiert es beim Einlesen richtig.
>
> In UTF-8 wird ein BOM am Fileanfang nicht ignoriert sondern als ZERO
> WIDTH NO-BREAK SPACE gelesen.
>
> Ist das das, was Du erwartest?
Ich erwarte hier gar nichts, ich bin nur neugierig, weil in der Ecke von
perl noch nicht unterwegs war. Ich lerne nur gerade von einem
Eingeweihten arkanes Geheimwissen :-)
>>> Das ist überwiegend konsistent. Die meisten Probleme auf dieser Ebene
>>> macht ja nicht Perl selbst, sondern sie werden durch den Datenfluss
>>> durch Module produziert (z.B. DBD::*). Und oft genug ist das was man
>> Was können die Module denn flacsh machen?
>
> Die Anzahl der möglichen Fehler ist unendlich :-(.
Wie immer :-(
> Zu den beliebtesten Fehlern zählen:
>
> * Verwechslungen von Byte- und Characterstrings, d.h., es wird das eine
> zurückgeliefert, obwohl es semantisch das andere sein sollte.
> * Herummurksen mit internen Funktionen wie _utf8_on/_utf8_off,
> ohne verstanden zu haben, was die tun.
> * Übergabe von Perl-Strings an bzw. von C-Library-Funktionen ohne
> korrekte Kodierung bzw. Dekodierung.
> * Das gleiche mit File-I/O.
Das ist doch schon mal eine Liste, mit der ich Code absuchen kann. Danke!