|
|
 |

|

 |

| Community » Perl: Allgemeines Forum |
|
ersetzen über mehrere Zeilen
|
Seitenanfang |
| Hallo zusammen! Ich habe eine HTML-Seite in folgendem Format:
<tr> <td>aaa</td> <td>aaa</td> </tr> <tr> <td>INHALT</td> </tr> <tr> ...
Ich will alle HTML-Zeilen in denen INHALT vorkommt komplett löschen, also von <tr> bis zum </tr>. Das habe ich so versucht: inhalt =~ s/<tr[^>]*>.+?INHALT.+?<\/tr>/TREFFER/sg;
Klappt aber nicht, es wird nicht nur die einzelne Zeile in der INHALT vorkommt, sondern auch die Zeile(n) davor entfernt. Jetzt raucht mir der Schädel und ich dreh mich im Kreis. Hat jemand 'ne schlaue Idee? Danke! Grüssle, Markus
Datum: 04.12.2005-15:00

|
re: ersetzen über mehrere Zeilen
|
Seitenanfang |
| Hallo Markus, warum liest du die HTML-Datei nicht zeilenweise ein und schreibst sie in eine neue Datei. Sollte dein Inhalt in einer Zeile vorkommen, lässt du die Zeile beim schreiben einfach aus. Wenn du die komplette Datei abgearbeitet hast, kannst du die alte Datei löschen und durch die neue ersetzen. Ich hoffe es ist das, was du suchst ... Gruß Patrick
Datum: 04.12.2005-17:23

|
re: ersetzen über mehrere Zeilen
|
Seitenanfang |
| Ne, das trifft's nicht. Das Problem ist, dass in einer Zeile das beginnende TR steht, dazwischen kommen dann die Spalten, in irgendeiner Spalte (jede auch in einer eigenen Zeile) steht evtl mein Suchbegriff und als letztes kommt wieder in einer neuen Zeile das schliessende /TR. Wenn ich also zeilenweise vorgehe, kann ich zwar den Inhalt finden, aber ich bin dann ja bereits schon einige Zeilen weiter und kann nicht mehr die ganze Tabellenzeile (eben von TR bis /TR) löschen. Grüssle, Markus
Datum: 04.12.2005-17:34

|
re: ersetzen über mehrere Zeilen
|
Seitenanfang |
Hi, ohne dass ich jetzt wirklich eine Lösung anbieten will, weil ich gerade keine Zeit habe, aber HTML mit regulären Ausdrücken abarbeiten zu wollen ist eine schmerzhafte Angelegenheit. Du musst dabei einfach zu viele Annahmen über den HTML Code machen (etwa da kommt ein Zeile mit tr, dann irgendwas mit INHALT, dann irgendwann ein /tr) - was aber wenn aus irgendeinem Grund eine der drei Annahmen nicht genau zutrifft? Dann scheitert das Skript.Ich würde das mit HTML::TreeBuilder machen, da ist es dann relativ einfach, tr-Objekte zu durchwandern und solche, die INHALT enthalten zu entfernen. Gruss, svenXY
Datum: 05.12.2005-16:26

|
re: ersetzen über mehrere Zeilen
|
Seitenanfang |
Hi, ich habe mir das jetzt doch nochmal angeschaut. Also mit ner einfachen RegEx geht es kaum. Das Problem ist, dass für das erste <tr... auf jeden Fall ein Match gefunden wird, der bis hinter das INHALT geht. Und dann wird es mit nichts ersetzt.Meine Lösund ist aber kaum komplizierter. Du trennst erst Deinen String jeweils am öffnenden <tr auf und schreibst die Ergebnisse in ein Array. Dann hängst Du das <tr wieder dran (es wird beim split entfernt) und dann gehst Du einfach durch alle Array Elemente durch (sie enthalten jetzt jeweils ein <tr>...</tr>) und schmeisst diejenigen raus, die INHALT enthalten:
#!/usr/bin/perl -w use strict;my $inhalt =<<'EOF'; <tr> <td>aaa</td> <td>aaa</td> </tr> <tr> <td>INHALT</td> </tr> <tr> <td>bbb</td> <td>bbb</td> </tr> EOF print "Davor:\n", $inhalt, "\n\n"; my @tr = split(/<tr/, $inhalt); # am <tr trennen @tr = map { "<tr$_" } @tr; # <tr an jedes Element wieder anhaengen @tr = grep { ! /INHALT/ } @tr; # jedes Array Element, das nicht INHALT enthaelt behalten print "danach:\n"; print join('', @tr); # Ausgabe
Ich empfehle Dir aber trotzdem, HTML::TreeBuilder anzuschauen, denn das ist auf jeden Fall empfehlenswert.Gruss, svenXY
Datum: 05.12.2005-18:53

|
re: ersetzen über mehrere Zeilen
|
Seitenanfang |
noch etwas eleganter ist
my @tr = split(/(?=<tr)/, $inhalt); # am <tr trennen und es nicht entfernen!
dann entfällt das map danach, da der Separator String nicht entfernt wird
Datum: 05.12.2005-19:06

|
TreeBuilder
|
Seitenanfang |
| Hi Sven! Vielen Dank für den Tip! Hab mir den Treebuilder mal angeschaut, das ist ja ein mächtiges Tool. Werd da mal etwas Zeit damit verbringen. Trotzdem hab die Hoffnung noch nicht ganz aufgegeben was Perl betrifft. Grüssle, Markus
Datum: 05.12.2005-23:41

|
re: TreeBuilder
|
Seitenanfang |
| Hi Markus, Du solltest definitiv nicht die Hoffnung aufgeben, was Perl betrifft! Ich habe Dein ursprüngliches Problem mal bei den PerlMonks gepostet, weil ich nicht so ganz glauben konnte, dass es nicht mit einer RegEx geht - und siehe da, es geht:
# und zwar als "negative lookahead" # (?:(?!<tr).)* reads as "0 or more characters which do not match the regex <tr". # It is to a regex-string what [^abc]* is to characters. $inhalt =~ s/<tr(?:(?!<tr>).)+?INHALT.+?<\/tr>//gsm;
Nur der Vollständigkeit halber und um mal wieder das Perl Motto zu bewahrheiten: TIMTOWTDIGruss, svenXY
Datum: 06.12.2005-07:59

|
re: TreeBuilder
|
Seitenanfang |
| Genial!! Das funktioniert einwandfrei!!! Hab's mir doch gedacht, dass es auch in Perl geht ;-)) Eine andere Frage noch dazu: weisst Du wie man den Ausdruck "INHALT" jetzt negieren kann? Also alle Zeilen löschen in denen nicht INHALT vorkommt? Wenn ich das mit (^INHALT) probiere geht irgendwas schief... Hab ich da was falsch verstanden? Grüssle, Markus
Datum: 06.12.2005-16:34

|
re: TreeBuilder
|
Seitenanfang |
Hi, nicht aus der hohlen Hand (und drei Versuchen). Wahrscheinlich auch mit so weinem Lookahead String.Ich würde es immer noch mit dem split machen oder eben besser mit TreeBuilder. Gruss, svenXY
Datum: 06.12.2005-18:17

|
re: TreeBuilder
|
Seitenanfang |
| OK, geht doch ganz einfach: $inhalt =~ s/<tr(?:(?!<tr>|INHALT).)+?<\/tr>//gsm; Heisst übersetzt: Fange bei <tr an und suche, solange kein weiteres <tr kommt und solange kein INHALT kommt, ansonsten mache mit dem nächsten <tr weiter Gruss, svenXY
Datum: 06.12.2005-18:20

|
re: TreeBuilder
|
Seitenanfang |
| OK, Du bist mein Held für diese Woche! Mille gracie!!! It's easy when you know how ;-)) Grüssle, Markus
Datum: 06.12.2005-20:30

|
|

|

|

|
 |

|

|
|