Forum: PC-Programmierung Regexbefehle unverständlich - perl


von Perl0Matiko (Gast)


Lesenswert?

Moin Community,

könnte mir jemand erklären, was genau diese Befehle machen?
1
//dieser Befehl ist mir noch klar. Der gematchte Ausdruck wird in den Skalar $Table geschrieben
2
 my ($Table) = ${ $Param{Data} } =~ m{ (<table \s+ class="TableSmall .*? </table>) }xms; 
3
4
    return 1 if !$Table; //wenn table leer dann zurück
5
6
    my $TableNew = $Table; //table in table new kopieren...
7
8
    //hier wirds knackikg, dieser Regex ersetzt irgendwie etwas, mir ist aber nicht genau klar, was hier passiert. Könnte mir das jemand erklären?
9
    $TableNew =~ s!(<thead> \s+ <tr> \s+ ((?:<th .*? </th> \s*)*)) (<th \s+ class="OverviewHeader \s+ Title\b .*? </th>)!"$1" . _SplitHeader($3)!exms; 
10
11
    // der Sinn von = () = erschließt sich mir leider auch nicht. - Jemand eine Erklärung?
12
    my $Position = () = $2 =~ m{(</th>)}g; 
13
14
    // add cells per row
15
    //auch hier habe ich arge Probleme zu verstehen, was genau wie übersetzt wird. Könnte mir auch hier jemand den Regex erklären?
16
    $TableNew =~ s!<tr [^>]*? > \s+ (?:<td .*? </td>\s* ){$Position} \K \s* (<td .*? </td>)!_SplitBody( $1 );!exmsg; 
17
18
    ${ $Param{Data} } =~ s{<table \s+ class="TableSmall .*? </table>}{$TableNew}xms; //die Ursprungstabelle wird überschrieben... auch klar
19
20
    return ${ $Param{Data} }; //ebenfalls klar...
21
}

Vielen Dank !

von (prx) A. K. (prx)


Lesenswert?


von Perl0Matiko (Gast)


Lesenswert?

A. K. schrieb:
> https://wiki.selfhtml.org/wiki/Perl/Reguläre_Ausdrücke

Danke für den Link, leider kann ich auch anhand dieser Informationen den 
Regex nicht auflösen.

Zu diesem Beispiel kann ich dort z.B. auch nichts finden.
1
my $Position = () = $2 =~ m{(</th>)}g;
1
  $TableNew =~ s!<tr [^>]*? > \s+ (?:<td .*? </td>\s* ){$Position} \K \s* (<td .*? </td>)!_SplitBody( $1 );!exmsg;

Hier verstehe ich nicht, was mit wem ersetzt wird. Die normale Syntax 
ist in meinen Augen
1
$TableNew =~ s/REGEXzuersetzen/ErsetzenMIt/;

Was genau der Regex sucht ist für mich nicht wichtig, lediglich was 
gesucht und was der zu ersetzende Teil ist.

von Thomas Z. (thomas_z41)


Lesenswert?

Bei $TableNew wurden statt /, ! zum trennen der Felder genutzt.
Also:
$TableNew =~ s!REGEXzuersetzen!ErsetzenMIt!Optionen;

von perlzulangsamNEoda (Gast)


Lesenswert?

Thomas Z. schrieb:
> Bei $TableNew wurden statt /, ! zum trennen der Felder genutzt.
> Also:
> $TableNew =~ s!REGEXzuersetzen!ErsetzenMIt!Optionen;

Danke, ich hatte schon die Vermutung, konnte in meinen Büchern aber 
keine Aussage finden, dass das ! als Trennzeichen verwendet werden darf.

Und hatte auf eine andere Funktion spekuliert.

von Marc S. (darkchaos)


Lesenswert?

RegExes sind eigentlich komplizierter als normales "Search & Replace",

So gilt z.B. \s für einen Space Character (Leertaste, TAB, Was auch 
immer...) und es gibt auch Quantoren (z.B. meint \s*: Keinen oder 
Beliebig Viele Leerzeichen an dieser Stelle).

Damit solltest du eigentlich alles entschlüsseln können.
Bleibt noch zu erwähnen dass man HTML eigentlich NICHT mit RegExes 
parsen kann/sollte. Das klappt zwar bei Vorgegebener Struktur, aber wenn 
du das Thema auf Englisch googlest siehst du, dass die Leute sich da 
nahezu bekriegen :P


Daher: Vielleicht tust du dich je nach Anwendungsfall mit einem XML/HTML 
Parser leichter.

von Tom (Gast)


Lesenswert?

Als Feldtrenner muss man -- wie schon erwähnt wurde -- nicht zwingend 
den üblichen / nehmen.

Das ist z.B. sinnvoll, wenn die Ausdrücke selbst viele / enthalten. Bei 
diesen müsste man sonst jeden einzelnen / mit \ escapen und ewig Fehler 
suchen, weil man einen vergessen hat.

http://perldoc.perl.org/perlop.html#Regexp-Quote-Like-Operators
"Any non-whitespace delimiter may replace the slashes."

von Eric B. (beric)


Lesenswert?

perlzulangsamNEoda schrieb:
> Danke, ich hatte schon die Vermutung, konnte in meinen Büchern aber
> keine Aussage finden, dass das ! als Trennzeichen verwendet werden darf.

Insofern ich weiß kann man fast beliebige Zeichen als Trennzeichen 
verwenden:

s/dies/mitjenem/g
s'dies'mitjenem'g
sZdiesZmitjenemZg

ist alles erlaubt und das gleiche. Ist vor allem hilfreich wenn "dies" 
oder "mitjenem" /-Zeichen enthält.

EDIT: Ah, Tom war schneller.

: Bearbeitet durch User
von perlzulangsamNEoda (Gast)


Lesenswert?

Tom schrieb:
> Als Feldtrenner muss man -- wie schon erwähnt wurde -- nicht
> zwingend
> den üblichen / nehmen.
>
> Das ist z.B. sinnvoll, wenn die Ausdrücke selbst viele / enthalten. Bei
> diesen müsste man sonst jeden einzelnen / mit \ escapen und ewig Fehler
> suchen, weil man einen vergessen hat.
>
> http://perldoc.perl.org/perlop.html#Regexp-Quote-L...
> "Any non-whitespace delimiter may replace the slashes."

Danke für den Tipp, dann kann ich mir soweit helfen.

>Das klappt zwar bei Vorgegebener Struktur, aber wenn
du das Thema auf Englisch googlest siehst du, dass die Leute sich da
nahezu bekriegen :P

Stimmt, aber ich konnte auf die schnelle keinen vernüpftigen Grund 
finden, warum das so nicht gemacht werden soll. Kannst du mir einen 
nennen?

von (prx) A. K. (prx)


Lesenswert?

1
Statt /pattern/ ist auch m{pattern} möglich.
Generell werden Klammern so verstanden, wie man es von Klammern 
erwartet.

: Bearbeitet durch User
von Marc S. (darkchaos)


Lesenswert?

Die korrekte Antwort wäre: Es geht um die Chomsky Hierarchie.

So gibt es z.B. 
http://ddi.cs.uni-potsdam.de/Forschung/SIMBA/export/mod-lklass/bilder/chomsky-h.png 
hier eine Auflistung.

Ein Vernünftiges Beispiel kann ich nur indirekt Liefern:
Stelle dir vor, du möchtest den Text eines Paragraph (<p>) parsen, dann 
ist es aber erlaubt ihn beliebig zu nesten:
1
/<p>(.*)</p>/
 funktioniert ja zunächst, aber was machst du bei:
1
<p>
2
 <p>Text</p>
3
</p>

Das wiederum ist auch kein Problem:
1
/<p>\s*<p>(.*)</p>\s*</p>/

ABER: Du könntest mit z.B.
1
/(<p>(.*)</p>)+
 zwar theoretisch unendliche Paragraphen auffangen, aber eben nur, wenn 
diese konsekutiv (nacheinander) vorkommen, aber eben nicht nested 
(Verzeigt).

Stelle dir vor, du hättest 5 Ebenen. Das wäre natürlich noch machbar, 
einfach copy und paste, aber was machst du bei UNENDLICH möglichen 
Ebenen?

Dafür nutzt man dann eher Bäume, sprich man geht immer eine Ebene tiefer 
und mit den Closing Tags dann wieder hoch.

Der Grund ist der, dass man eben nicht S -> <p>S</p> sondern NUR S -> 
<p>S oder S-> s</p> definieren kann, sprich nur Sprachen, wie man sie 
bei der Handschrift hätte (Ein Zeichen nach dem anderen, aber nicht 
wieder vorne was einfügen).

ALLERDINGS: Wenn die Struktur bekannt ist (z.B. die maximale Tiefe 
vorgegeben ist), dann kannst du sehr wohl ein RegEx dafür bauen, es wird 
aber irgendwann eklig und aufwendig und das bei reduzierter Freiheit 
(der Struktur)

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Perl0Matiko schrieb:
> my $Position = () = $2 =~ m{(</th>)}g;

Auf der rechten Seite hast du den "match"-Operator "m".  Das Argument
(wonach gesucht wird) ist diesmal nicht in // oder || oder !!
gefasst, sondern in {}.  Gematcht wird $2, also die zweite Fundstelle
der vorangegangenen Suche.

Das Ergebnis des match-Operators ist (außer, dass er $1 neu setzt,
und zwar mit dem gefundenen String "</th>") ein Wahrheitswert, der
darüber aussagt, ob etwas gefunden worden ist.

Das mit () kannte ich auch noch nicht ;), scheint ein numerisches
Ergebnis zu erzwingen, also 0 oder 1.  Wenn man das weglässt, bekommt
man bei "no match" statt der 0 einen leeren Wert.

Ansonsten waren reguläre Ausdrücke schon immer "write-only".

von (prx) A. K. (prx)


Lesenswert?

Tom schrieb:
> Das ist z.B. sinnvoll, wenn die Ausdrücke selbst viele / enthalten. Bei
> diesen müsste man sonst jeden einzelnen / mit \ escapen und ewig Fehler
> suchen, weil man einen vergessen hat.

Auch als "leaning toothpick syndrome" bekannt:
https://en.wikipedia.org/wiki/Leaning_toothpick_syndrome

von Marc S. (darkchaos)


Lesenswert?

Ich kann meinen Beitrag nicht mehr Editieren, daher:

Hier ist noch eine wie ich finde schöne, weitergehende Erklärung dazu
http://stackoverflow.com/a/6752487

von Ralf D. (doeblitz)


Lesenswert?

Jörg W. schrieb:
> Perl0Matiko schrieb:
>> my $Position = () = $2 =~ m{(</th>)}g;
[...]
> Das mit () kannte ich auch noch nicht ;), scheint ein numerisches
> Ergebnis zu erzwingen, also 0 oder 1.  Wenn man das weglässt, bekommt
> man bei "no match" statt der 0 einen leeren Wert.

Damit bringst du die Match-Expression in List-Context, das Ergebnis ist 
also eine Liste mit n Treffern, die Zuweisung bringt das in 
Scalar-Context, wodurch dann die Zahl der Elemente gespeichert wird.

Eine Alternative wäre "0+(EXPRESSION)", wodurch das Ergebnis der 
Expression auch in eine Zahl umgewandelt würde und 0+'' ergibt eben 0. 
Ist evtl. besser verständlich, aber auch nicht perfekt.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Ralf D. schrieb:
> Eine Alternative wäre "0+(EXPRESSION)"

Ja, die hatte ich noch irgendwie im Hinterkopf.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.