Verstaendnisproblem regulärer Ausdruck HTML Table

Verstaendnisproblem regulärer Ausdruck HTML Table

am 31.05.2006 13:52:03 von StefanKehrer

Hallo Newsgroup

Es geht um folgendes. Mit Hilfe eines regulären Ausdrucks versuche ich
alle Tabellen aus einer HTML Seite herauszufiltern. Mir ist bewußt
daß da einige Einschränkungen bestehen bezüglich verschachtelter
Tabellen,aber das ist erst mal nicht so tragisch.

Diesen Quellcode lasse ich ausführen:

if(( $content=3D~ /(]*>.+<\/table>)/s))
{
print "$&";
}
In $content steht der Inhalt der gesamten HTML Seite.

Was ich erwarten würde ist das $& den aktuell gemachten Ausdruck
enthält also sowas ausgibt wie:

irgendwas


Aber stattdessen wird der Quelltext der gesamten Seite ausgegeben.

Wo liegt mein Denkfehler, welche Variable sollte das von mir erwartete
Ergebniss ausgeben,oder ist was mit meinem regulären Ausdruck nicht in
Ordnung?

Gruß

Stefan Kehrer

Re: Verstaendnisproblem regulärer Ausdruck HTML Table

am 31.05.2006 14:20:02 von Wolf Behrenhoff

StefanKehrer@gmail.com schrieb:
> Diesen Quellcode lasse ich ausführen:
>
> if(( $content=~ /(]*>.+<\/table>)/s))
> {
> print "$&";
> }
> In $content steht der Inhalt der gesamten HTML Seite.
>
> Was ich erwarten würde ist das $& den aktuell gemachten Ausdruck
> enthält also sowas ausgibt wie:
>
>

irgendwas

>
> Aber stattdessen wird der Quelltext der gesamten Seite ausgegeben.

Das glaube ich nicht. Folgender Code
d:\>perl -we
"$c='
bla
';
$c =~ /(]*>.+<\/table>)/s; print $&"

gibt aus:
bla


> Wo liegt mein Denkfehler, welche Variable sollte das von mir erwartete
> Ergebniss ausgeben,oder ist was mit meinem regulären Ausdruck nicht in
> Ordnung?

Gleich mehrere Dinge:
- geschachtelte Tabellen gehen nicht (hast du bereits genannt)
- mehrere Tabellen in einen Dokument funktionieren nicht, weil du mit .+
greedy matchst (d.h. wenn mehrere Tabellen vorhanden sind, werden sie
von dem ersten bis zum letzen
gematcht)
- du verwendest überflüssigerweise $& (nimm $1 - du hast es ja in den
Klammern stehen, was du suchst)
- wenn du das HTML nicht selbst erzeugst/genau kennst, dann solltest du
einen HTML-Parser nehmen und keine REs.

Wolf

Re: Verstaendnisproblem regulärer Ausdruck HTML Table

am 31.05.2006 15:00:36 von StefanKehrer

Wolf Behrenhoff schrieb:

> Das glaube ich nicht. Folgender Code
> d:\>perl -we
> "$c=3D'

bla
';
> $c =3D~ /(]*>.+<\/table>)/s; print $&"
>
> gibt aus:
>
bla

>

Geglaubt hab ich es auch nicht. ;) Aber es war nun mal so, hab nix am
geposteten Code verändert. :)
Hab jetzt das greedy .+ ersetzt durch .+? , und jetzt ist das Ergebnis
schon eher wie gedacht. :)

> > Wo liegt mein Denkfehler, welche Variable sollte das von mir erwartete
> > Ergebniss ausgeben,oder ist was mit meinem regulären Ausdruck nicht in
> > Ordnung?
>
> Gleich mehrere Dinge:
> - geschachtelte Tabellen gehen nicht (hast du bereits genannt)
> - mehrere Tabellen in einen Dokument funktionieren nicht, weil du mit .+
> greedy matchst (d.h. wenn mehrere Tabellen vorhanden sind, werden sie
> von dem ersten bis zum letzen
gematcht)
> - du verwendest überflüssigerweise $& (nimm $1 - du hast es ja in den
> Klammern stehen, was du suchst)
> - wenn du das HTML nicht selbst erzeugst/genau kennst, dann solltest du
> einen HTML-Parser nehmen und keine REs.
>

-Hab jetzt das greedy entfernt, und lass es mit Option g laufen,
scheint zu funktionieren

-$& hatte ich nur,weil mir das Ergebniss von $1 auch nicht gefiel, und
ich dachte es würd dadurch besser. ;)

-Hab mir mal HTML::TableExtract angeguckt, aber soweit ich das sehe
muss man dazu wissen wie groß eine Tabelle ist, und in welcher Tiefe
sie liegt. Also in welcher Ebene.
Also wurd noch nicht so ganz schlau drauß. :) Aber hatte ich auch
schon in Erwägung gezogen, erstmal will ich aber die Dateien so
kleinhacken. Danach kann ich ja die reinen Tabellen damit bearbeiten.

Danke für die Tipps :)

Re: Verstaendnisproblem regulärer Ausdruck HTML Table

am 31.05.2006 18:20:11 von Ferry Bolhar

Wolf Behrenhoff:

> - du verwendest überflüssigerweise $& (nimm $1 - du hast es ja in den
> Klammern stehen, was du suchst)

Zumindest bis Perl 5.6 war es so, dass $& (und seine "Brüder" $´ und $`)
einen große Auswirkung auf die Performance eines Skripts hatten (es wurde
langsamer), und daher empfohlen wurde, es nicht (und stattdessen Klammern
und $1,$2,...) zu verwenden. Ich weiß nicht, ob das in den aktuellen Perl-
Versionen auch noch so ist, möchte aber nur der Vollständigkeit halber
darauf hinweisen. Ich verwende in meinen Skripts $& und Konsorten daher
grundsätzlich nicht (es gibt immer Alternativen!).

Schöne Grüße aus Wien,

Ferry

--
Ing. Ferry Bolhar
Municipality of Vienna, Department 14
A-1010 Vienna / AUSTRIA
E-mail: bol@adv.magwien.gv.at

Re: Verstaendnisproblem regulärer Ausdruck HTML Table

am 31.05.2006 22:22:28 von StefanKehrer

Ferry Bolhar schrieb:


> Zumindest bis Perl 5.6 war es so, dass $& (und seine "Brüder" $=B4 und =
$`)
> einen große Auswirkung auf die Performance eines Skripts hatten (es wur=
de
> langsamer), und daher empfohlen wurde, es nicht (und stattdessen Klammern
> und $1,$2,...) zu verwenden. Ich weiß nicht, ob das in den aktuellen Pe=
rl-
> Versionen auch noch so ist, möchte aber nur der Vollständigkeit halber
> darauf hinweisen. Ich verwende in meinen Skripts $& und Konsorten daher
> grundsätzlich nicht (es gibt immer Alternativen!).
>
> Schöne Grüße aus Wien,
>
> Ferry
>

Ja stimmt. Steht auch noch so in der aktuellen Doku, beeinträchtigt
die Perfomance. Es ist da aber auch erklärt(durch eine andere
Funktion) wie man das umgeht. Den Teil hab ich mir aber nicht
durchgelesen.

Re: Verstaendnisproblem regulärer Ausdruck HTML Table

am 01.06.2006 09:44:45 von Mirco Wahab

Thus spoke StefanKehrer@gmail.com (on 2006-05-31 22:22):

> Ferry Bolhar schrieb:
>> Zumindest bis Perl 5.6 war es so, dass $& (und seine "Brüder" $´ und $`)
>> einen große Auswirkung auf die Performance eines Skripts hatten ...
>
> Ja stimmt. Steht auch noch so in der aktuellen Doku, beeinträchtigt
> die Perfomance. Es ist da aber auch erklärt(durch eine andere
> Funktion) wie man das umgeht. Den Teil hab ich mir aber nicht
> durchgelesen.

So wahr das auch ist, für so irrelevant halte
ich das jedoch in 90 v. 100 Fällen (heutzutage).

Aber es gehört wohl inzwischen zur 'guten Kultur'
\$[`´&] nicht zu verwenden.

Merken würde man es wahrscheinlich, wenn
die zusätzliche Kopiererei im 'Sekundenbereich'
liegt, also bei Pattern-Targets, deren (akkumulierte)
Länge der Speichertransferrate (Byte/sec) des Hosts
größenordnungsmäßig nahekommt.

(Man korrigiere mich bitte, wenn ich falsch liege.)

Viele Grüße

Mirco

Re: Verstaendnisproblem regulärer Ausdruck HTML Table

am 01.06.2006 12:57:17 von Ferry Bolhar

Mirco Wahab:

> Merken würde man es wahrscheinlich, wenn die zusätzliche Kopiererei im
'Sekundenbereich'
> liegt, also bei Pattern-Targets, deren (akkumulierte) Länge der
Speichertransferrate (Byte/sec)
> des Hosts größenordnungsmäßig nahekommt.

So viel ich mich erinnern kann, war das Problem folgendes:

Wenn in einer Regex Ausdrücke geklammert werden (um die Variablen $1, $2,
.... zu
verwenden), muss Perl von dem zu ersetzenden Text vorher eine Kopie anlegen,
damit
mit dieser die Variablen befüllt werden können, wenn der Originaltext durch
die Substitution
gelöscht oder modifiziert wird. Dieses Kopieren kostet Resourcen (Zeit und
Speicher), die
eingespart werden können, wenn keine Ausdrücke geklammert werden.

Werden aber die Variablen $`, $& oder $´ verwendet, muss auch dann, wenn
keine
Klammern verwendet wurden, diese Kopie erzeugt werden, da diese Variable ja
genauso
Teile des Textes enthalten wie $1, $2.... Da der Compiler im Vorhinein nicht
wissen kann,
_wann_ auf eine der drei Variablen zugegriffen wird, generiert er für
_jeden_ regulären
Ausdruck den Code zum Anlegen der Kopie des Textes, sobald _irgendwo_ im
Programm
(oder in einem der vom Programm verwendeten Module) eine dieser drei
Variablen auf-
taucht. Und das kann bei langen Texten sehr ineffizient werden, besonders im
Hinblick
darauf, dass diese drei Variablen ja wohl kaum bei _jeder_ Regex tatsächlich
benötigt
werden, aber eben dennoch immer eine Textkopie angelegt wird.

IIRC gab es einer der älteren 5er Version (5.003 oder so) Versuche, das zu
ändern, um
eine effizientere Verwendung von $`, $& und $´ zu ermöglichen; das Resultat
war, dass
die Regex-Engine in bestimmten Situationen nicht mehr richtig funktionierte.
Darauf hat
man das wieder ausgebaut und rät seither "offiziell" von der Benutzung der
drei Variablen
ab und stattdessen zum Einsatz von $1, $2,..., mit denen die Funktion von $&
und
Konsorten nachgebildet werden kann.

Der Perl-Core speichert das erkannte Aufscheinen einer dieser Variablen in
einer
eigenen (internen) Variable, PL_sawampersand. Ist diese Variable auf 1
gesetzt,
wurde eine oder mehrere der drei Variablen im Code entdeckt und es muss
immer
eine Textkopie angelegt werden. Das CPAN-Modul Devel::SawAmpersand macht
den Zugriff auf diese Variable von Perl aus möglich. Interessant ist auch
B::FindAmpersand, das ausgibt, in welcher Datei in welcher Zeile einer der
drei
Variablen gefunden wurde.

Vermutlich ist es richtig, dass sich die Verwendung von $& bei den meisten
Programmen kaum auswirken wird. Seine konsequente Vermeidung hilft aber
Probleme in Situationen zu verhindern, in denen es sich doch auswirken
würde.

LG, Ferry

--
Ing. Ferry Bolhar
Municipality of Vienna, Department 14
A-1010 Vienna / AUSTRIA
E-mail: bol@adv.magwien.gv.at

Re: Verstaendnisproblem regulärer Ausdruck HTML Table

am 01.06.2006 13:21:33 von Frank Seitz

Ferry Bolhar wrote:

> Wenn in einer Regex Ausdrücke geklammert werden (um die Variablen $1, $2,
> ... zu
> verwenden), muss Perl von dem zu ersetzenden Text vorher eine Kopie anlegen,
> damit
> mit dieser die Variablen befüllt werden können, wenn der Originaltext durch
> die Substitution
> gelöscht oder modifiziert wird.

Das verstehe ich nicht. $1, $2, ... sind doch Teilstrings, die
die Regex-Engine intern ermittelt. Wozu muss dazu vorher eine Kopie
des String angelegt werden? Ein einfacher Pattern-Match (m//)
modifiziert auch nichts an dem String.

> Vermutlich ist es richtig, dass sich die Verwendung von $& bei den meisten
> Programmen kaum auswirken wird.

Darin sehe ich einen Widerspruch zu dem, was Du vorher gesagt hast.

BTW: Dein Text war grauselig umgebrochen.

Grüße
Frank
--
Dipl.-Inform. Frank Seitz; http://www.fseitz.de/
Anwendungen für Ihr Internet und Intranet
Tel: 04103/180301; Fax: -02; Industriestr. 31, 22880 Wedel

Re: Verstaendnisproblem regulärer Ausdruck HTML Table

am 02.06.2006 10:53:45 von Ferry Bolhar

Frank Seitz:

>> Wenn in einer Regex Ausdrücke geklammert werden (um die Variablen $1, $2,
>> ... zu
> > verwenden), muss Perl von dem zu ersetzenden Text vorher eine Kopie
anlegen,
>> damit
>> mit dieser die Variablen befüllt werden können, wenn der Originaltext
durch
>> die Substitution gelöscht oder modifiziert wird.
>
> Das verstehe ich nicht. $1, $2, ... sind doch Teilstrings, die
> die Regex-Engine intern ermittelt. Wozu muss dazu vorher eine Kopie
> des String angelegt werden?

Schau dir folgendes Beispiel an:

my $text = 'irgendwas';

if ($text =~ /(ge)/) {
$text = "Gefunden:";
print "$text: $1\n";
}

Würde der Inhalt von $text nicht vorher gesichert, könnte man nach
der Änderung nicht mehr auf $1 zugreifen. Warum? Nun:

$1 und seine Freunde enthalten nicht den eigentlichen Text, sondern
sie enthalten nur _Zeiger_ auf jene Teile des Textes, der auf die jeweiligen
Zeichenmuster gepasst hat. Im obigen Beispiel wird also der gesamte Text
"Gefunden" kopiert und für $1 wird sein Zeiger auf das "g" der Kopie
und ein Längenwert von 2 gesetzt. Das heißt, $1, $2,... und - falls
verwendet - auch $& usw. enthalten keine Strings, sondern teilen sich
alle einen gemeinsamen String, auf den durch Setzen von Zeigern und
Längen die jeweiligen Teilstrings definiert werden. Daher sind diese
Variablen auch alle per Definition read-only; andernfalls wäre es möglich,
z.B. durch Verändern von $1 auch $2, $3 usw. mit zu verändern.

> Ein einfacher Pattern-Match (m//) modifiziert auch nichts an dem String.

Siehe oben.Vielleicht habe ich mich da unklar ausgedrückt. Es geht
darum, dass nicht für alle $1... Variablen alle Teilstrings kopiert werden
müssen (was bei langen Strings extrem ineffizient wäre), sondern der
gesamte String nur einmal, und jede Variable wird so gesetzt, dass sie
aus dieser Kopie den jeweils passenden Teil extrahiert.

> > Vermutlich ist es richtig, dass sich die Verwendung von $& bei den
meisten
> > Programmen kaum auswirken wird.
>
> Darin sehe ich einen Widerspruch zu dem, was Du vorher gesagt hast.

Jein. Der Tipp, auf die Verwendung von $& und Konsorten zu
verzichten, stammt aus Anfang/Mitte der Neunziger Jahre, wo das
Schreiben "schneller" und "speicherschonender" Programme noch
weit wichtiger war als heute. Ich persönlich halte von Warnungen
"Verwende das bloß nicht!" wenig. Wenn man mir nahelegt, etwas,
das es gibt, trotzdem nicht zu verwenden, dann möchte ich zumindest
wissen, _warum_, sprich, ich möchte wissen, was hinter den Kulissen
abläuft und mich so selber in die Lage versetzen, entscheiden zu
können, wann ich jetzt ein Feature (weitgehend) unbesorgt verwenden
kann und wann nicht. Daher habe ich mich diesbezüglich auch schon
vor etlichen Jahren schlau gemacht.

Mein diesbezüglicher Hinweis, bei der Verwendung von $& ...
vorsichtig zu sein, war lediglich ein Hinweis, da es auch heute noch
Fälle gibt, wo seine Verwendung tatsächlich zu Performanceeinbußen
führen kann. Die Fälle mögen selten sein, aber sie sind vorhanden.
Daher der Hinweis. Aber ich denke, anhand meiner Erklärung
sollte ja nun jeder selber in der Lage zu sein, beurteilen zu können,
wie sinnvoll die jeweilige Verwendung von $&... ist.

In Perl6 wird es diese Variablen jedenfalls nicht mehr geben.

> BTW: Dein Text war grauselig umgebrochen

Liegt möglicherweise daran, dass ich ihn nicht auf meinem PC
geschrieben habe. Sorry!

LG, Ferry

--
Ing. Ferry Bolhar
Municipality of Vienna, Department 14
A-1010 Vienna / AUSTRIA
E-mail: bol@adv.magwien.gv.at