[Vienna-pm] utf8 string als hash-key
Aristoteles Pagaltzis
pagaltzis at gmx.de
Mon Sep 21 09:37:56 PDT 2009
* max <prozessor13 at gmx.net> [2009-09-21 10:25]:
> On Sep 20, 2009, at 11:05 PM, Aristoteles Pagaltzis wrote:
> >Du machst mit annähernd 100%er Wahrscheinlichtkeit etwas
> >falsch. Du verstehst auch mit ähnlicher Wahrscheinlichtkeit
> >nicht, was du damit tatsächlich anstellst. (Das ist nicht
> >persönlich gemeint: es ist etwas, was nur wenige richtig
> >verstehen. Sogar die Perl- Doku selbst ist streckenweise
> >verwirrt.)
>
> ja.. das seh ich auch so, wollte eben nur wissen was ich falsch
> mach
Du fummelst mit der internen Repräsentation von Strings herum.
Das willst du in 99.9999% der Fälle *nicht* machen.
> nur bin ich grad draufgekommen, dass diese eh gar nicht das
> problem ist. peinlich. hab mich aber leider so darauf
> festgefahren, dass ichs erst wem erzaehlen hab muessen, um das
> selber zu checken.
Mach dir nichts draus, das ist normal. :-)
Another effective technique is to explain your code to
someone else. This will often cause you to explain the bug
to yourself. Sometimes it takes no more than a few
sentences, followed by an embarrassed “Never mind, I see
what’s wrong. Sorry to bother you.” This works remarkably
well; you can even use non-programmers as listeners. One
university computer center kept a teddy bear near the help
desk. Students with mysterious bugs were required to explain
them to the bear before they could speak to a human
counselor.
—Kernighan & Pike, _The Practice of Programming_, Kap. 1
* max <prozessor13 at gmx.net> [2009-09-21 10:35]:
> On Sep 20, 2009, at 11:29 PM, Josef wrote:
> >_utf8_{on,off} setzen nur das interne Flag um! Und ändern
> >nichts an den Daten.
>
> ja das weiss ich, das war auch genau meine absicht. ich wollt
> einfach den strings als bytes ansehen, ohne der utf8-logik
Das willst du nicht. »ß« kann abhängig vom Flag wahlweise als
Byte DF oder als Bytefolge C3 9F dargestellt und BEDEUTET
DASSELBE in beiden Fällen. Du willst die Zeichenkette encoden,
nicht einfach an irgendwelchen Perl-Eingeweiden herumfummeln,
sodaß aus einem »ß« immer dasselbe Ergebnis wird, nicht mal so
und mal so.
> es kommen immer utf8-strings daher, darum auch diese annahme
> (was jetzt programmiertechnisch sicher nicht 1A ist ;)
Gewöhn dir das ab. Denk nicht über das UTF-8-Flag nach.
> ja und nein, denn in perl5.8.9 funktioniert es ja. das ist ja
> das komische!
Das ist Programming by Coincidence. Wenn du es falsch machst, und
es funktioniert zufälligerweise trotzdem, heißt das nicht, daß du
es richtig gemacht hast.
* max <prozessor13 at gmx.net> [2009-09-21 12:30]:
> so und nochmal.
>
> jetzt hab ich das beweis-script:
>
> use strict;
> use utf8;
> use Data::Dumper;
> binmode STDOUT, 'utf8';
>
> sub x {
> my %hash = map {
> my $k = $_;
> utf8::encode($k);
> $k => 'bytes'
> } @_;
> foreach (keys %hash) {
> my $k = $_;
> utf8::decode($k);
> $hash{$k} = 'utf8';
> }
> return \%hash;
> }
>
> my $x = 'öäü';
> my $h = x($x);
> print Data::Dumper->Dumpperl([$h]);
> print Data::Dumper->Dump([$h]);
>
> liefert unter perl5.8.9 korrekterweise:
>
> $VAR1 = {
> 'öäü' => 'bytes',
> 'öäü' => 'utf8'
> };
> $VAR1 = {
> 'öäü' => 'bytes',
> "\x{f6}\x{e4}\x{fc}" => 'utf8'
> };
>
> und unter perl 5.10 falscherweise:
>
> $VAR1 = {
> 'öäü' => undef,
> 'öäü' => 'bytes',
> 'öäü' => ${\$VAR1->{'öäü'}}
> };
> $VAR1 = {
> "\x{f6}\x{e4}\x{fc}" => 'utf8',
> 'öäü' => 'bytes',
> "\x{f6}\x{e4}\x{fc}" => undef
> };
Hier ist das Gegenbeweis-Skript:
use strict;
use utf8;
use Data::Dumper;
use Encode;
binmode STDOUT, ':encoding(UTF-8)';
sub x {
my %hash = map {
my $k = $_;
encode('UTF-8', $k) => 'bytes';
} @_;
foreach (keys %hash) {
my $k = $_;
$hash{decode('UTF-8', $k)} = 'utf8';
}
return \%hash;
}
my $x = 'öäü';
my $h = x($x);
print Data::Dumper->Dumpperl([$h]);
print Data::Dumper->Dump([$h]);
Das liefert bei mir die erwartete Ausgabe.
Ein paar Punkte zum Mitschreiben:
• Niemals den `:utf8` binmode verwenden, denn der macht effektiv
nur `_utf8_on`/`_utf8_off` statt den Input/Output tatsächlich
zu de-/enkodieren.
• Aus `utf8` nur `upgrade`/`downgrade` verwenden, und dann auch
nur falls man mit kaputten XS-Modulen zu tun hat und die Daten
in Latin-1 passen.
• Sonst IMMER `decode`/`encode` aus Encode nehmen.
• Das Encoding immer »UTF-8« schreiben, nicht »utf8«; letzteres
prüft nur minimalst auf Gültigkeit. (Das kann bis hin zu
Sicherheitslücken führen, weil das Programm dann evlt. dazu zu
bringen ist, Output zu erzeugen, der von andere Programmen
falsch interpretiert wird.)
• perlunitut und perlunifaq lesen.
* Josef <e9427749 at stud4.tuwien.ac.at> [2009-09-21 17:45]:
> Abgesehen von perl5.10 Seltsamkeiten verwurschtelt dein Modul
> definitiv das utf8-Flag. Also mal ein Fehler des Moduls!
> Wenn es denn nicht gebe, wärst Du mit den perl5.10 Problemen
> nicht in Kontakt gekommen.
>
> Älterer xs-Code ist oft nicht utf8-aware.
Stimme zu.
Gruß,
--
Aristoteles Pagaltzis // <http://plasmasturm.org/>
More information about the Vienna-pm
mailing list