ImpressumFrank Seitz Wassermühlenstr. 2 25436 Uetersen E-Mail: fsfseitz.de Tel.: +49-176-78243503 Alle Artikel Inhaltsverzeichnis Rechtliche Hinweise Code auf GitHub Code auf meta::cpan KategorienAbonnieren |
Donnerstag, 10. September 2015Perl: UTF-8 und ISO-8859-1 Dateien erkennen und automatisch dekodierenIdealerweise sollte ein Programm sowohl mit ISO-8859-1 als auch mit UTF-8 Input-Dateien umgehen können, und zwar am besten so, dass das Encoding nicht explizit angegeben werden muss. Lässt sich dies realisieren? Ja, indem das Programm sich den Inhalt der Datei "ansieht", entscheidet, welches Encoding vorliegt und den Text entsprechend dekodiert. Im Falle von Perl kann hierfür das Modul Encode::Guess genutzt werden. Es ist Teil des Perl-Core und damit in jeder Perl-Installation enthalten. Es wird mit use Encode::Guess;
geladen. Wir nutzen die objektorientierte Schnittstelle des Moduls. Theoretisch sollte folgender Sechszeiler die Aufgabe erledigen: Encode::Guess->set_suspects('iso-8859-1');
my $dec = Encode::Guess->guess($text);
if (!ref $dec) {
die "ERROR: $dec\n";
}
$text = $dec->decode($text);
Erläuterung:
Leider funktioniert diese Implementierung nicht! Denn wir stellen folgendes fest:
Woran liegt das? Die Ursache ist, dass jede UTF-8-Datei formal auch eine ISO-8859-1-Datei ist. Denn jede Datei ist formal eine ISO-8859-1-Datei, selbst eine Binärdatei wie z.B. ein JPEG-Bild. Das liegt daran, dass ISO-8859-1 ein Ein-Byte-Encoding ist, bei dem alle 256 Werte belegt sind. Es ist also fruchtlos und hinderlich, mit Encode::Guess auf ISO-8859-1 testen zu wollen. Ist die Unterscheidung von UTF-8 und ISO-8859-1 also nicht möglich? Doch, sie ist möglich, wenn auch nicht mit den Mechanismen von Encode::Guess allein. Denn auch wenn UTF-8 formal gültiges ISO-8859-1 darstellt, gilt nicht die Umkehrung, dass jeder ISO-8859-1 Text valides UTF-8 darstellt. Es ist sogar sehr unwahrscheinlich, dass ein realer ISO-8859-1 Text, gleichzeitig valides UTF-8 ergibt, beinahe ebensowenig, wie dass ein ISO-8859-1 Text ein JPEG-Bild ergibt. Unter Berücksichtigung dieser Tatsache können wir die Unterscheidung von ISO-8859-1 und UTF-8 hinreichend sicher vornehmen: my $dec = Encode::Guess->guess($text);
if (ref $dec) {
$text = $dec->decode($text);
}
elsif ($dec =~ /No appropriate encodings found/i) {
$text = Encode::decode('iso-8859-1',$text);
}
else {
die "ERROR: $dec\n";
}
Erläuterung:
Dieser Ansatz ("Wenn etwas nach UTF-8 aussieht, ist es auch UTF-8, sonst betrachten wir es als ISO-8859-1") funktioniert. Das Ganze als vollständige Implementierung einer Perl-Klasse File mit einer einzelnen Methode decode(): package File;
use strict;
use warnings;
use Encode::Guess ();
# ---------------------------------------------------------------------------
=encoding utf8
=head1 NAME
File - Klasse mit Datei-Operationen
=head1 METHODS
=head2 decode() - Lies und dekodiere eine Textdatei
=head3 Synopsis
$text = $class->decode($file);
=head3 Description
Lies Textdatei $file und liefere den dekodierten Inhalt zurück.
Als Character Encoding erwarten wir Unicode (speziell UTF-8) oder
Latin1 (ISO-8859-1).
=cut
# ---------------------------------------------------------------------------
sub decode {
my ($class,$file) = @_;
# Datei einlesen
local $/ = undef;
open my $fh,'<',$file or die "ERROR: open failed: $file ($!)\n";
my $text = <$fh>;
close $fh;
# Encoding ermitteln und Text dekodieren
my $dec = Encode::Guess->guess($text);
if (ref $dec) {
# Wir dekodieren Unicode
$text = $dec->decode($text);
}
elsif ($dec =~ /No appropriate encodings found/i) {
# Erwarteter Fehler: Wir dekodieren Latin1
$text = Encode::decode('iso-8859-1',$text);
}
else {
# Unerwarteter Fehler
die "ERROR: $dec\n";
}
return $text;
}
# ---------------------------------------------------------------------------
=head1 AUTHOR
Frank Seitz, L<http://fseitz.de/>
=head1 LICENSE
This code is free software. You can redistribute it and/or modify
it under the same terms as Perl itself.
=cut
# ---------------------------------------------------------------------------
1;
# eof
LinksMontag, 8. Juni 2015Perl: Text im richtigen Character Encoding ausgebenJedes Kommandozeilenprogramm, das Texte und Meldungen mit Non-ASCII-Zeichen (z.B. Umlauten) aufs Terminal ausgibt, sollte die aktuelle Locale-Einstellung berücksichtigen, damit sichergestellt ist, dass alle Zeichen richtig dargestellt werden. Es reicht nicht aus, dass die Ausgabe unter der eigenen Terminal-Einstellung (z.B LANG=xx_XX.UTF-8) korrekt aussieht. Denn hat der Anwender ein abweichendes Character-Encoding konfiguriert (z.B. LANG=xx_XX.ISO-8859-1), sieht er anstelle der Non-ASCII-Zeichen Zeichensalat, wenn das Programm nicht explizit in dieses Encoding wandelt (in diesem Fall sähe er zwei Zeichen statt einem für jeden Umlaut). In Perl lässt sich diese nicht-triviale Aufgabe elegant durch Verwendung des Pragma open in Verbindung mit der Angabe ':locale' lösen. Die Zeile use open OUT=>':locale'; am Anfang des Programms sorgt dafür, dass für alle Ausgabeströme (einschl. STDOUT und STDERR) ein I/O-Layer eingerichtet wird, der die geschriebenen Daten automatisch gemäß dem in der Umgebung eingestellten Character-Encoding enkodiert. Beispiel: Die folgenden beiden Programme geben für beliebig in der Umgebung eingestellte Zeichensätze mit deutschen Umlauten - u.a. UTF-8 und ISO-8859-1 - zwei Zeilen mit Umlauten aus, die korrekt dargestellt sein sollten. Hierbei erzeugt print die Ausgabe via STDOUT und warn die Ausgabe via STDERR. Quelle mit einem Latin1-Editor erstellt: #!/usr/bin/env perl
use strict;
use warnings;
use open OUT=>':locale';
my $str = "ÄÖÜäöüß";
print "$str\n";
warn "$str\n";
# eof .
Quelle mit einem UTF-8-Editor erstellt: #!/usr/bin/env perl
use strict;
use warnings;
use utf8; # <- UTF-8 Quelltext
use open OUT=>':locale';
my $str = "ÄÖÜäöüß";
print "$str\n";
warn "$str\n";
# eof .
LinksFreitag, 24. Mai 2013Unicode: UTF-8 validierenZum Validieren von UTF-8 kann GNU iconv genutzt werden. Der Aufruf $ iconv -f UTF-8 FILE >/dev/null liefert Exitcode 0, wenn die Datei FILE valides UTF-8 enthält, andernfalls 1. Im Falle von nicht-validem UTF-8 schreibt iconv zusätzlich eine Fehlermeldung nach stderr: iconv: illegal input sequence at position N Hierbei ist N der Byte-Offset, an dem die (erste) ungültige Byte-Sequenz gefunden wurde. Samstag, 27. August 2011Linksammlung: UTF-8 PortierungAllgemein
MySQL
Perl
Mittwoch, 13. Januar 2010Unicode: ISO-8859-1 nach UTF-8 konvertiereniconv - Convert encoding of given files from one encoding to another $ iconv -f ISO-8859-1 -t UTF-8 INPUT >OUTPUT tcs - translate character sets $ tcs -f 8859-1 INPUT >OUTPUT
(Seite 1 von 1, insgesamt 5 Einträge)
|
Kalender
StatistikLetzter Artikel:
08.07.2024 21:11 157 Artikel insgesamt
Links
|