[gelöst] Text-Parsing-Problem mit Perl

bitmuncher

Senior-Nerd
Ich bin gerade dabei mit Perl einen Parser zu schreiben, der Dateien einliest und daraus spezielle Informationen extrahiert. Unter anderem steht in den Dateien auch ein Charset. Um an das Charset zu kommen nutze ich

Code:
        if($line =~ m/charset/i) {
            $line =~ m/charset=(.*)/i;
            $charset = $1;
            if($charset =~ m/^\"/i) {
                $charset =~ m/\"(.*)\"/i;
                $charset = $1;
            }
            print "Charset: $charset\n";
        }

Und hier kommt das Problem in's Spiel. Die Dateien enthalten nämlich manchmal mehrere Charset-Informationen, von denen ich nur 2 Formate benötige und die 3 verschiedene Formate haben können. Hier mal die möglichen Formate:

Code:
Content-Type: text/plain;
  charset="iso-8859-1"

Code:
Content-Type: text/plain;charset=ISO-8859-1

bzw.

Content-Type: text/html;charset=ISO-8859-1

und zu guter Letzt können HTML-Sachen in den Dateien sein, die dann etwa wie folgt ausssehen:

Code:
<meta http-equiv=3D"Content-Type" content=3D=
"text/html; charset=3DISO-8859-1">

wobei bei dieser letzten Variante das Meta-Tag manchmal in einer Zeile steht und manchmal auf mehrere Zeilen verteilt ist. Ich benötige allerdings nur die ersten beiden Varianten.

Vor dem raussuchen des Charsets dekodiere ich natürlich das quoted-printabe-Format mit

Code:
    my $res = shift;
    $res =~ s/\r\n/\n/g;
    $res =~ s/[ \t]+\n/\n/g;
    $res =~ s/=\n//g;
    if (ord('A') == 193) {
        if (ord('[') == 173) {
            $res =~ s/=([\da-fA-F]{2})/Encode::encode('cp1047',Encode::decode('iso-8859-1',pack("C", hex($1))))/ge;
        }
        elsif (ord('[') == 187) {
            $res =~ s/=([\da-fA-F]{2})/Encode::encode('posix-bc',Encode::decode('iso-8859-1',pack("C", hex($1))))/ge;
        }
        elsif (ord('[') == 186) {
            $res =~ s/=([\da-fA-F]{2})/Encode::encode('cp37',Encode::decode('iso-8859-1',pack("C", hex($1))))/ge;
        }
    }
    else { # ASCII style machine
        $res =~ s/=([\da-fA-F]{2})/pack("C", hex($1))/ge;
    }
    $res;

so dass das Meta-Tag danach in ISO vorliegt (bzw. vorliegen sollte ;) ). Hat jemand eine effektive Lösung ohne tausende Überprüfungen (idealerweise mit 1-2 Regexen), wie ich das Charsets des HTML-Tags ausschliessen kann? Das Problem liegt für mich hier darin, daß das Meta-Tag auf mehrere Zeilen verteilt sein kann, aber nicht muß und daß ich die Dateien zeilenweise einlese (while($line = <FILE>)...). Das Programm "weiß" daher nicht immer, ob in der Zeile davor ein Meta-Tag begonnen hat, wenn der Abschnitt 'charset="ISO-8859-1"' am Anfang der Zeile steht. Falls jemand auch nur den Ansatz einer Idee hat, dann immer her damit. Mit einem Schalter habe ich es auch schon versucht, der einfach auf 1 gesetzt wurde, wenn in einer Zeile ein HTML-Meta-Tag gefunden wurde, allerdings kann nach dem HTML-Code durchaus auch ein Charset enthalten sein, das ich noch benötige, was dann natürlich durch das gesetzte Flag geflissentlich ignoriert wurde.
 
Moin,

vielleicht hab ich es auch falsch verstanden aber setzt doch das Flag nach dem finden von </meta> wieder zurück auf 0/false. wobei natürlich noch zu prüfen währe ob es mit </meta> oder <meta .... /> begrenzt ist.

noch einfacher währe es wohl die http header daten von den html daten zu trennen, also zwischen <html> und </html> alles ausschneiden, und erst dann zu parsen.

ich denke das grösste problem stellt das zeilenweise prüfen dar. wenn die daten unbedingt als array vorliegen müssen, so würde ich zumindest fürs parsen das array zu einem string zusammensetzten. dadurch könnte man dann auch einen regex verwenden, der die daten gruppiert zurück gibt.

hab leider keine erfahrung mit perl, sonst würde ich etwas code posten.

MfG
 
Die Idee den Meta-Tag abzufangen ist ein Ansatz. Daran hatte ich garnicht gedacht. Werde das mal versuchen. Danke für den Dankanstoß. :)

Edit: Hat soweit funktioniert, auch wenn aus dem Schalter ein Counter der Meta-Tags geworden ist. :)
 
Zurück
Oben