Bitte beachten Sie zunächst die Dokumentation - die utf8
Modul sollte sólo in der Form 'use utf8;' verwendet werden, um anzugeben, dass Ihr Quellcode UTF-8 anstelle von Latin-1 ist. Verwenden Sie keine der utf8-Funktionen.
Perl unterscheidet zwischen Bytes und UTF-8-Strings. Im Bytemodus weiß Perl nicht, welche Kodierung Sie verwenden, und wird Latin-1 verwenden, wenn Sie es ausgeben. Nehmen Sie zum Beispiel das Euro-Zeichen (€). In UTF-8 sind dies 3 Bytes, 0xE2, 0x82, 0xAC. Wenn Sie die Länge dieser Bytes ausgeben, wird Perl 3 zurückgeben. Auch hier spielt die Kodierung keine Rolle. Es kann jedes Byte oder jede Kodierung sein, legal oder illegal.
Wenn Sie die Encode
Modul und rufen Encode::decode("UTF-8', $bytes)
erhalten Sie eine neue Zeichenkette, bei der das sogenannte UTF8-Flag gesetzt ist. Perl weiß nun, dass Ihre Zeichenkette in UTF-8 vorliegt, und gibt die Länge 1 zurück.
Das Problem, das utf8::valid
gilt nur für die zweite Art von Zeichenfolge. Ihre Zeichenketten sind wahrscheinlich in der ersten Form, dem Byte-Modus, und utf8::valid
gibt einfach true für alles in Byte-Form zurück. Dies ist in der perldoc dokumentiert.
Die Lösung besteht darin, Perl dazu zu bringen, Ihre Byte-Strings als UTF-8 zu dekodieren und alle Fehler zu erkennen. Dies kann mit FB_CROAK gemacht werden, wie brian d foy erklärt:
my $ustring =
eval { decode( 'UTF-8', $byte_string, FB_CROAK ) }
or die "Could not decode string: $@";
Sie können dann diesen Fehler abfangen und die ungültigen Zeichenfolgen überspringen.
Oder wenn Sie wissen, dass Ihr Code größtenteils UTF-8 ist, mit ein paar ungültigen Sequenzen hier und da, können Sie verwenden:
my $ustring = decode( 'UTF-8', $byte_string );
die den Standardmodus von FB_DEFAULT
und ersetzt ungültige Zeichen durch U+FFFD, das Unicode-Ersetzungszeichen (Raute mit Fragezeichen).
In den meisten Fällen können Sie die Zeichenfolge dann direkt an Ihren Datenbanktreiber übergeben. Bei einigen Treibern müssen Sie die Zeichenkette zunächst wieder in die Byteform zurückkodieren:
my $byte_string = encode('UTF-8', $ustring);
Es gibt auch Regexe online, die Sie verwenden können, um auf gültige UTF-8-Sequenzen zu prüfen, bevor Sie decode
(siehe andere Stack Overflow-Antworten). Wenn Sie diese Regexe verwenden, müssen Sie keine Kodierung oder Dekodierung vornehmen.
Schließlich verwenden Sie bitte UTF-8
statt utf8
in Ihren Aufrufen an decode
. Letztere ist laxer und lässt einige ungültige UTF-8-Sequenzen (wie Sequenzen außerhalb des Unicode-Bereichs) durch.