Poldi: Text zwischen zwei HTML-Tags

Hallo!

Ich moechte aus einem Link z.B. <a href="http://www.bla.bla.net">Das ist ein Link</a> den
Text rausbekommen. Also es sollte praktisch das, was zwischen > und < steht in eine andere
Variable kopiert werden. Aber wirklich nur der erste Text zwischen diesen Zeichen. Hab schon
im Archiv gestoebert, aber nur Loeschen von Html-Tags gefunden. Gibt es eigentlich irgendwo im
Web weiterfuehrende Literatur zu solchen Extraktionsproblemen?

Gruesse

Poldi.

  1. Ich moechte aus einem Link z.B. <a href="http://www.bla.bla.net">Das ist ein Link</a> den
    Text rausbekommen. Also es sollte praktisch das, was zwischen > und < steht in eine andere
    Variable kopiert werden. Aber wirklich nur der erste Text zwischen diesen Zeichen. Hab schon
    im Archiv gestoebert, aber nur Loeschen von Html-Tags gefunden.

    Angenommen, ich verstehe Deine Aufgabenstellung richtig und Du hast den entsprechenden Text in einer Variablen $htmltext (das hinzukriegen ist ein anderes Problem wegen des möglichen Zeilenumbruchs in HTML), dann denke ich, Du willst diesen Wert analysieren mit dem regular expression

    if ($htmltext =~ /<a[^>]>(.*?)</a>/i)
       {
         my $linktext = $1;
         # ... und hier die Weiterverarbeitung
       }
    (Das "i" am Ende macht die Sache case-insensitiv wegen des "a" im Tag; das "?" macht den regular expression weniger gierig, weil Du ja mehrere Treffer haben könntest.)

    Bedenke, daß Du damit *nur* den *ersten* Treffer innerhalb Deines Textes bekommst - wenn Du mehrere hast, wird es etwas aufwendiger (Rest der Zeile zwischenspeichern und Schleife drum herum).

    Meine 'Lösung' ist nicht idiotensicher: Es könnte sein, daß jemand innerhalb des HREF-Wertes in "" eingeschlossen ein ">"-Zeichen verwendet ... :-(((
    (Hoffentlich erlaubt kein Dateisystem solche Zeichen innerhalb von Dateinamen.)

    Gibt es eigentlich irgendwo im
    Web weiterfuehrende Literatur zu solchen Extraktionsproblemen?

    Mit regular expressions kann man alles machen. ;-)

    1. Hallo Michael und Poldi

      if ($htmltext =~ /<a[^>]>(.*?)</a>/i)
         {
           my $linktext = $1;
           # ... und hier die Weiterverarbeitung
         }

      Müsste nach [^>] nicht noch ein * hin?

      Meine 'Lösung' ist nicht idiotensicher: Es könnte sein, daß jemand innerhalb des HREF-Wertes in "" eingeschlossen ein ">"-Zeichen verwendet ... :-(((
      (Hoffentlich erlaubt kein Dateisystem solche Zeichen innerhalb von Dateinamen.)

      Hier habe ich noch eine kompliziertere Variante:

      if ($htmltext =~ /<a(\s+[a-z]+\s*=\s*("[^"]*"[^>\s]*))*\s*>(.*?)</a>/is)
         {
           my $linktext = $3;
           # ... und hier die Weiterverarbeitung
         }

      Gibt es eigentlich irgendwo im
      Web weiterfuehrende Literatur zu solchen Extraktionsproblemen?

      Mit regular expressions kann man alles machen. ;-)

      Vielleicht noch ein paar Links dazu:
      <../../tgcg.htm>
      http://www.phy.uni-bayreuth.de/~btpa25/perl/perl_reg.html
      http://www.heise.de/ix/artikel/1998/11/178/

      Gruss
      Andreas

      1. if ($htmltext =~ /<a[^>]>(.*?)</a>/i)
        Müsste nach [^>] nicht noch ein * hin?

        Uuups - natürlich. (Sorry.)

        1. if ($htmltext =~ /<a[^>]>(.*?)</a>/i)
          Müsste nach [^>] nicht noch ein * hin?

          Uuups - natürlich. (Sorry.)

          Tatsaechlich hat aber weder das eine noch das andere funktioniert. Keine Ahnung wieso.
          Hab's dann so gemacht: if ($htmltext =~ />(.+)</a>/)
          und dann hat's ploetzlich geklappt. Hab ich aus irgendeinem Buch. Nur weiss ich nicht
          WIESO das funktioniert hat und das andere nicht ...

          Gute N8

          Poldi

          1. Hallo Poldi

            if ($htmltext =~ /<a[^>]>(.*?)</a>/i)
            Müsste nach [^>] nicht noch ein * hin?

            Uuups - natürlich. (Sorry.)

            Tatsaechlich hat aber weder das eine noch das andere funktioniert. Keine Ahnung wieso.

            Bei </a> muss noch das / maskiert werden:
            if ($htmltext =~ /<a[^>]*>(.*?)</a>/i)

            Hab's dann so gemacht: if ($htmltext =~ />(.+)</a>/)

            Dies funktioniert allerdings nur, wenn der zu durchsuchende Text aus nur *einem* HTML-Tag besteht und </a> klein geschrieben ist.

            und dann hat's ploetzlich geklappt. Hab ich aus irgendeinem Buch. Nur weiss ich nicht
            WIESO das funktioniert hat und das andere nicht ...

            Beim zweiten Beispiel wurde / maskiert. Allerdings wurde beim maskieren etwas übertrieben.
            if ($htmltext =~ />(.+)</a>/)
            würde auch reichen.

            Gruss
            Andreas

      2. if ($htmltext =~ /<a(\s+[a-z]+\s*=\s*("[^"]*"[^>\s]*))*\s*>(.*?)</a>/is)

        Da der Schwanzabschneider alle | entfernt (so ein wichtiges Zeichen ;-), das ganze noch mit Unicode-codiertem Zeichen:
        if ($htmltext =~ /<a(\s+[a-z]+\s*=\s*("[^"]*"|[^>\s]*))*\s*>(.*?)</a>/is)

        Gruss
        Andreas

        1. Da der Schwanzabschneider alle entfernt (so ein wichtiges Zeichen ;-)

          Schon wahr - aber für irgendein Zeichen als Strukturtrenner innerhalb des Such-Indexes mußte sich Stefan nun mal entscheiden, und dieses Zeichen darf dann halt sonst nirgends mehr vorkommen.

          Man könnte das natürlich ändern (und beide Skripte   - auch die 'Suchmaschine' muß dieses Zeichen ja kennen - anpassen und den 25-MB-Index durch einen Konverter jagen und ... ;-).

          1. Da der Schwanzabschneider alle entfernt (so ein wichtiges Zeichen ;-)

            Schon wahr - aber für irgendein Zeichen als Strukturtrenner innerhalb des Such-Indexes mußte sich Stefan nun mal entscheiden, und dieses Zeichen darf dann halt sonst nirgends mehr vorkommen.

            Man könnte das natürlich ändern (und beide Skripte   - auch die 'Suchmaschine' muß dieses Zeichen ja kennen - anpassen und den 25-MB-Index durch einen Konverter jagen und ... ;-).

            Man könnte ja den Schwanzabschneider zumindest so anpassen, dass er die | nur in der Index-Datei löschen würde. In den Archivdateien stören sie ja nicht, oder?

            Gruss
            Andreas

            1. Man könnte ja den Schwanzabschneider zumindest so anpassen, dass er die nur in der Index-Datei löschen würde. In den Archivdateien stören sie ja nicht, oder?

              Da ist was dran.

              Natürlich stimmt dann der Inhalt der Postings nicht mehr mit dem Suchindex überein, d. h. wer dann ein Posting durch "" im Suchbegriff zu finden erwartet, fällt auf die Nase ...

    2. Hi!

      ... und erstmal danke fuer die rege Anteilname! Dachte ich mir doch, dass eine Menge Leute da
      ihren Spass dran haben werden :-)

      Angenommen, ich verstehe Deine Aufgabenstellung richtig und Du hast den entsprechenden Text in einer Variablen $htmltext

      Habe ich.

      (das hinzukriegen ist ein anderes Problem wegen des möglichen Zeilenumbruchs in HTML),

      Kommt nicht vor. Ist eine von mir selbst generierte Datei. Ich kann von gewissen Voraussetzungen
      also ausgehen.

      dann denke ich, Du willst diesen Wert analysieren mit dem regular expression

      Ich will da eigentlich nichts analysieren sondern nur den Text herausbekommen.

      if ($htmltext =~ /<a[^>]>(.*?)</a>/i)

      Ist das noetig? ich weiss ja mit SICHERHEIT, dass es sich um einen Link in HTML handelt.

      {
           my $linktext = $1;

      Wo ist jetzt dieses $1 her?
      Bezieht sich das auf den Ausdrueck in der Klammer?
      Wie sieht das dann ohne If aus?

      (Das "i" am Ende macht die Sache case-insensitiv wegen des "a" im Tag;

      Aso.
      Und wenn ich weiss, dass das a immer klein ist, dann ist das ja nicht noetig ...

      das "?" macht den regular expression weniger gierig, weil Du ja mehrere Treffer haben könntest.)

      Ja, ist was dran. Also mit ? gibt's dann tatsaechlich nur den ersten Treffer?!

      Bedenke, daß Du damit *nur* den *ersten* Treffer innerhalb Deines Textes bekommst -

      Genau das will ich!

      wenn Du mehrere hast, wird es etwas aufwendiger (Rest der Zeile zwischenspeichern und Schleife drum herum).

      Ja, war mir klar :-)

      Meine 'Lösung' ist nicht idiotensicher: Es könnte sein, daß jemand innerhalb des HREF-Wertes in "" eingeschlossen ein ">"-Zeichen verwendet ... :-(((

      Nein nein, ich kann davon ausgehen, dass das eher nicht vorkommen wird.

      (Hoffentlich erlaubt kein Dateisystem solche Zeichen innerhalb von Dateinamen.)

      Hm. Weiss ich jetzt auch nicht.

      Gruesse und vielen Dank nochmal an alle

      Poldi.

      1. Kommt nicht vor. Ist eine von mir selbst generierte Datei. Ich kann von gewissen Voraussetzungen also ausgehen.

        Schön für Dich - das vereinfacht die Sache.

        dann denke ich, Du willst diesen Wert analysieren mit dem regular expression
        Ich will da eigentlich nichts analysieren sondern nur den Text herausbekommen.

        Ja, aber diese beiden Vorgänge sind in Perl nicht voneinander zu trennen, wie Du gleich sehen wirst.

        if ($htmltext =~ /<a[^>]>(.*?)</a>/i)
        Ist das noetig? ich weiss ja mit SICHERHEIT, dass es sich um einen Link in HTML handelt.

        Mag sein. Aber Perl weiß es nicht. Und erst durch das Analysieren findet Perl die Stellen, an denen es die Zeichenkette herausschneiden soll ...

        {
             my $linktext = $1;
        Wo ist jetzt dieses $1 her?
        Bezieht sich das auf den Ausdrueck in der Klammer?

        Ganz genau.
        Die in runden Klammern umschlossenen Ausdrücke werden den impliziten Variablen $1, $2 usw. zugewiesen - hätte ich die Klammern weggelassen, dann wäre das direkte Ergebnis des "if" dasselbe gewesen, aber ohne diesen Seiteneffekt (der in Deinem Falle gerade erwünscht ist).

        Wie sieht das dann ohne If aus?

        Du kannst wohl auch einfach
           $htmltext =~ /<a[^>*]>(.*?)</a>/i;
        ohne "if" drum herum schreiben.
        Aber nach meiner Erfahrung hat eine "this can't happen:"-Meldung im "else"-Zweig des "if" noch nie geschadet, und CPU-Zeit kostet sie auch fast keine. Für mich gehört es zum guten programmierstil, so etwas abzufragen (und im Quelltext zu dokumentieren, daß es "eigentlich" nie vorkommen kann). Du kannst ja an anderer Stelle im Programm einen Fehler einbauen - etwa beim Generieren Deiner Links - und würdest ihn dann hier netterweise gefunden bekommen.

        (Das "i" am Ende macht die Sache case-insensitiv wegen des "a" im Tag;
        Aso.
        Und wenn ich weiss, dass das a immer klein ist, dann ist das ja nicht noetig ...

        ... und *das* würde die Suche dann schneller machen.
        (Kein Wunder, denn bei case-insensitiver Suche muß Perl fast immer zwei Zeichen für den nächsten Vergleich ausprobieren statt nur eines. Das kannst Du im Archiv-Suchskript selbst ausprobieren.)

        das "?" macht den regular expression weniger gierig, weil Du ja mehrere Treffer haben könntest.)
        Ja, ist was dran. Also mit ? gibt's dann tatsaechlich nur den ersten Treffer?!

        Ohne "?" ist jeder regular expression "gierig", versucht also, ein möglichst großes Stück zu matchen. Mit ihm ist er nicht gierig und versucht, ein möglichst kleines Stück zu matchen.
        Probiere es aber trotzdem erst mal aus ...

        Bedenke, daß Du damit *nur* den *ersten* Treffer innerhalb Deines Textes bekommst -
        Genau das will ich!

        Dachte ich mir - mit zwei Stücken hättest Du wenig anfangen können. ;-)

        Meine 'Lösung' ist nicht idiotensicher: Es könnte sein, daß jemand innerhalb des HREF-Wertes in "" eingeschlossen ein ">"-Zeichen verwendet ... :-(((
        Nein nein, ich kann davon ausgehen, dass das eher nicht vorkommen wird.

        Glück gehabt - Du willst also die einfachste aller Lösungen.

        1. if ($htmltext =~ /<a[^>]>(.*?)</a>/i)

          Ach ja: Es gibt natürlich irgend so einen CPAN-Modul, der ein HTML-Dokument vollautomatisch analysieren und eine Liste aller gefundenen Links zurückliefern kann ... wenn nicht letzten Donnerstag meinem Intranetserver die rootvg-Platte gestorben wäre, könnte ich auch nachsehen, wie der heißt. :-(((

          1. if ($htmltext =~ /<a[^>]>(.*?)</a>/i)

            Ach ja: Es gibt natürlich irgend so einen CPAN-Modul, der ein HTML-Dokument vollautomatisch analysieren und eine Liste aller gefundenen Links zurückliefern kann ... wenn nicht letzten Donnerstag meinem Intranetserver die rootvg-Platte gestorben wäre, könnte ich auch nachsehen, wie der heißt. :-(((

            Es heisst HTML ... wer haette das gedacht :-))
            Ich hab das auch schon entdeckt, und zwar im "Perl Kochbuch", das mir bis jetzt auch schon
            gute Dienste geleistet hat, allerdings bietet es fuer eher triviale Probleme keine Loesung ...

            Gruesse

            Poldi.