Gerd: Reg expr: Wie erfasse ich URLs im Fließtext?

Hi,

ich möchte eine oder auch mehrere URLs aus einem eingelesenen Fließtext (html) erfassen, ich habs hiermit versucht, aber das hat nicht so funktioniert, wie ich wollte:

$pattern = "<a(.*)href=[^>]*>(.*)</a>";

Dabei dachte ich, $pattern beschreibt einen Ausdruck <a(mit eventuellem weiterem Text)href=[und zwar nicht >]und nochmal eventuelle Zeichen, gefolgt von >, dann wieder Zeichen und zum Schluß </a>.

Womit dann bspw. <a href="http://www.domain.de/blabla/datei.html">Link</a> vollständig erfasst sein sollte.

Ist aber in der Praxis so, daß über </a> hinaus erfasst wird.

Warum denn das?

Grüße, Gerd

  1. Hallo,

    Ich hatte mal so etwas im Einsatz:

    function replace_uri($str, $length = 30) {  
      
      $pattern = '#(^|[^\"=]{1})(http://|ftp://|mailto:|news:|https://)([^\s<>]{1,'.$length.'})([^\s<>]*)([\s\n<>]|$)#sm';  
      
      return preg_replace($pattern,"\\1<a href=\"\\2\\3\\4\">\\2\\3</a>\\5",$str);  
    }
    

    Grüße
    Jeena Paradies

    --
    Mit »links« im Netz ein Abenteuer ohne Grafische Oberfläche | Jlog | Gourmetica Mentiri
    1. Hallo,

      Ich hatte mal so etwas im Einsatz:

      function replace_uri($str, $length = 30) {

      $pattern = '#(^|[^"=]{1})(http://|ftp://|mailto:|news:|https://)([^\s<>]{1,'.$length.'})([^\s<>]*)([\s\n<>]|$)#sm';

      return preg_replace($pattern,"\1<a href="\2\3\4">\2\3</a>\5",$str);
      }

      
      >   
      >   
      > Grüße  
      > Jeena Paradies  
        
        
      Hi Jeena,  
        
      nene, genau das Gegenteil brauche ich.. ;-)  
        
      Danke, Gerd
      
      1. Hallo,

        nene, genau das Gegenteil brauche ich.. ;-)

        Haha ach so das hatte ich nicht kappiert, na dann auf's neue:

        '#<a[^>]+href\s*=\s*("([^"]+)"|\'([^\']+)\')[^>]*>(.+)</a>#Ui'

        Das findet bei mir alle Links, leider auch die, die in HTML Kommentaren deinn sind.

        Grüße
        Jeena Paradies

        --
        Mit »links« im Netz ein Abenteuer ohne Grafische Oberfläche | Jlog | Gourmetica Mentiri
        1. Hi Jena,

          klasse. Der klappt prima :-)

          preg_match_all(
            '#<a[^>]+href\s*=\s*("([^"]+)"|'([^']+)')[^>]*>(.+)</a>#Ui',
            $zeile,
            $rx_matches, PREG_PATTERN_ORDER);

          Jetzt mal weiter daran knabbern :-) Jetzt muß ich noch die Links ändern. Wird schon :-)
          Sonst frag ich weiter.

          Grüße, Gerd

          1. Hi Jena,

            klasse. Der klappt prima :-)

            preg_match_all(
              '#<a[^>]+href\s*=\s*("([^"]+)"|'([^']+)')[^>]*>(.+)</a>#Ui',
              $zeile,
              $rx_matches, PREG_PATTERN_ORDER);

            Jetzt mal weiter daran knabbern :-) Jetzt muß ich noch die Links ändern. Wird schon :-)
            Sonst frag ich weiter.

            Grüße, Gerd

            Die nun im assoziativen array enthaltenen Links zu ändern sollte nicht das Problem sein, aber wie bekomme ich die geänderten Links danach in $zeile wieder an ihre ursprüngliche Postion?

            Oder wäre das in einer Schleife besser (im Sinne der Performance) gewesen? Wenn ja, wie würde ich dann vorgehen müssen?

            Grüße, Gerd

            1. Hallo,

              Die nun im assoziativen array enthaltenen Links zu ändern sollte nicht das Problem sein, aber wie bekomme ich die geänderten Links danach in $zeile wieder an ihre ursprüngliche Postion?

              Ich glaube dann suchst du am ehesten: preg_replace()

              Oder wäre das in einer Schleife besser (im Sinne der Performance) gewesen?

              Habe es zwar nicht gemessen aber intuitiv würde ich sagen nein, das ding ist in C geschrieben und nimmt sich das ganze sowieso eines nach dem anderen vor, da jetzt noch den Umweg über PHP zu gehen glaube ich ist unsinnig.

              Grüße
              Jeena Paradies

              --
              Mit »links« im Netz ein Abenteuer ohne Grafische Oberfläche | Jlog | Gourmetica Mentiri
              1. Hallo,

                Die nun im assoziativen array enthaltenen Links zu ändern sollte nicht das Problem sein, aber wie bekomme ich die geänderten Links danach in $zeile wieder an ihre ursprüngliche Postion?

                Ich glaube dann suchst du am ehesten: preg_replace()

                Hallo,

                ich glaub nicht. Denn ich muß ja noch jede Menge Zwischenoperationen (if-abfragen, explode, substr, usw.) mit den Links anstellen. Die wäre ich mit preg-replace gezwungen, in einem Schritt zu machen.

                Grüße, Gerd

                1. Hallo (und frohe Ostern),

                  ich glaub nicht. Denn ich muß ja noch jede Menge Zwischenoperationen (if-abfragen, explode, substr, usw.) mit den Links anstellen. Die wäre ich mit preg-replace gezwungen, in einem Schritt zu machen.

                  Wenn du preg_match_all() benutzt, kannst du als Flag PREG_OFFSET_CAPTURE angeben. Dann wird das "Treffer"-Array zusätzlich um die Startposition der gefundenen Zeichenketten erweitert. Diese Information hilft dir dann beim Ersetzen mit substr_replace() weiter.

                  Aber auch mit preg_replace() (oder zumindest "nahen Verwandten) ist es möglich, umfangreicheren PHP-Code in die Verarbeitung einzubinden. Es gibt dazu zwei Möglichkeiten:

                  1. Du erweiterst dein Suchmuster um den Modifikator "/e". Dann kannst du den "Ersetzen"-Parameter (ähnlich wie bei eval()) mit PHP-Code erweitern.

                  2. Umfangreichere Manipulationen an den gefundenen Zeichenketten ermöglicht eine benutzerdefinierte Funktion, wenn du statt preg_replace() die Funktion preg_replace_callback() verwendest.

                  MffG
                  EisFuX

                  --
                  ... Suchmaschinen-Blog ...
                  1. Danke an Dich.
                    Hat prima geklappt, ich hab PREG_OFFSET_CAPTURE und substr_replace()  genutzt. Jetzt läufts!
                    Danke für die Antwort, gerade deshalb, weil der Thread ja schon etwas älter war und ich drauf und dran war, per Doppelposting nochmal auf mein nach wie vor bestehendes Problem hinzuweisen ;-)

                    Grüße, Gerd

                    Hallo (und frohe Ostern),
                    substr_replace() weiter.

                    ich glaub nicht. Denn ich muß ja noch jede Menge Zwischenoperationen (if-abfragen, explode, substr, usw.) mit den Links anstellen. Die wäre ich mit preg-replace gezwungen, in einem Schritt zu machen.

                    Wenn du preg_match_all() benutzt, kannst du als Flag PREG_OFFSET_CAPTURE angeben. Dann wird das "Treffer"-Array zusätzlich um die Startposition der gefundenen Zeichenketten erweitert. Diese Information hilft dir dann beim Ersetzen mit substr_replace() weiter.

                    Aber auch mit preg_replace() (oder zumindest "nahen Verwandten) ist es möglich, umfangreicheren PHP-Code in die Verarbeitung einzubinden. Es gibt dazu zwei Möglichkeiten:

                    1. Du erweiterst dein Suchmuster um den Modifikator "/e". Dann kannst du den "Ersetzen"-Parameter (ähnlich wie bei eval()) mit PHP-Code erweitern.

                    2. Umfangreichere Manipulationen an den gefundenen Zeichenketten ermöglicht eine benutzerdefinierte Funktion, wenn du statt preg_replace() die Funktion preg_replace_callback() verwendest.

                    MffG
                    EisFuX

  2. Hi Gerd,

    ich möchte eine oder auch mehrere URLs aus einem eingelesenen Fließtext (html) erfassen, ich habs hiermit versucht, aber das hat nicht so funktioniert, wie ich wollte:

    $pattern = "<a(.*)href=[^>]*>(.*)</a>";

    Dabei dachte ich, $pattern beschreibt einen Ausdruck <a(mit eventuellem weiterem Text)href=[und zwar nicht >]und nochmal eventuelle Zeichen, gefolgt von >, dann wieder Zeichen und zum Schluß </a>.

    Womit dann bspw. <a href="http://www.domain.de/blabla/datei.html">Link</a> vollständig erfasst sein sollte.

    Ist aber in der Praxis so, daß über </a> hinaus erfasst wird.

    '<a(.*)' - erfasst nach "<" und "a" eine beliebige Zahl (nahezu) beliebiger Zeichen, und da PCRE von Natur aus gierig sind, nehmen sie immer die längste passende Zeichenkette, die sie finden können. Steht also im HTML-Quelltext hinter dem
    <a href="">...
    noch eins, dann wird das miterfasst.

    Ich würde das besser so machen (PCRE):

      
    preg_match_all(  
      '/\<a\s+href=([\"\']?)([^>]*)\1\s*\>([^<]*)\<\/a\>/',  
      $haystack,  
      $rx_matches  
    );  
    print_r($rx_matches);  
    
    

    Das dürfte die Fälle abdecken, in denen außer dem href-Attribut kein weiteres vorkommt.

    MffG
    EisFuX

    --
    ... Suchmaschinen-Blog ...
    1. '<a(.*)' - erfasst nach "<" und "a" eine beliebige Zahl (nahezu) beliebiger Zeichen, und da PCRE von Natur aus gierig sind, nehmen sie immer die längste passende Zeichenkette, die sie finden können. Steht also im HTML-Quelltext hinter dem
      <a href="">...
      noch eins, dann wird das miterfasst.

      Hi EisFux,

      genau das ist der Fall und genau das passiert auch :-)

      Ich würde das besser so machen (PCRE):

      preg_match_all(
        '/<a\s+href=(["']?)([^>])\1\s>([^<]*)</a>/',
        $haystack,
        $rx_matches
      );
      print_r($rx_matches);

      
      >   
        
        
        
      Mal ausprobieren.  
        
      Dank Dir  
        
      Gerd  
        
        
        
      
      > Das dürfte die Fälle abdecken, in denen außer dem href-Attribut kein weiteres vorkommt.  
      >   
      > MffG  
      > EisFuX
      
    2. Sorry, aber tuts leider nicht...
      Ausgabe:
      Array ( [0] => Array ( ) [1] => Array ( ) [2] => Array ( ) [3] => Array ( ) )

      Grüße, Gerd

      1. Sorry, aber tuts leider nicht...
        Ausgabe:
        Array ( [0] => Array ( ) [1] => Array ( ) [2] => Array ( ) [3] => Array ( ) )

        Mhmm, das ist komisch. Bei mir hats mit einer Test-HTML-Datei geklappt. Bist du sicher, dass $haystack auch HTML-Text als Inhalt hat? Wenn ja, wie sehen die Links im Quelltext aus? Möglicherweise sind noch einige Attribute mehr drin als nur "href". Dann müsste man den RegEx anpassen.

        MffG
        EisFuX

        --
        ... Suchmaschinen-Blog ...
        1. Sorry, aber tuts leider nicht...
          Ausgabe:
          Array ( [0] => Array ( ) [1] => Array ( ) [2] => Array ( ) [3] => Array ( ) )

          Mhmm, das ist komisch. Bei mir hats mit einer Test-HTML-Datei geklappt. Bist du sicher, dass $haystack auch HTML-Text als Inhalt hat? Wenn ja, wie sehen die Links im Quelltext aus? Möglicherweise sind noch einige Attribute mehr drin als nur "href". Dann müsste man den RegEx anpassen.

          MffG
          EisFuX

          Hi Eisfux,

          Hier ein umgesetzter Originallink:

          <A HREF="http://www.domain.de/verz/uverz1/uverz1a/datei.html" TARGET=_blank>Linktext</A> (rauskopiert aus $haystack, daher noch die Backshlashes.

          Würde mich gerne mit Deinem Ansatz befassen. Der ist mir irgendwie sympatisch.

          Ich habe jetzt mal analog mit dem Ansatz von dieser Seite experimentiert und das wie folgt umgesetzt:

          http://www.php-faq.de/q/q-regexp-links-finden.html

          ----------------------- schnipp -----------------------------------
          $pattern = '=^(.*)<a(.*)href="?(\S+)"([^>]*)>(.*)</a>(.*)$=msi';
          while (preg_match($pattern, $zeile, $txt))
          {
            /* $txt[3] enthält die gewünschte URL. */
            echo $txt[3]."\n";

          $link = explode("/",$txt[3]);
          $rest = substr($link[4], 0, 5); // für Kontext unwichtig
          $f= substr($link[4], 5, 1); // für Kontext unwichtig
          $t=substr($link[6], 0, 6); // für Kontext unwichtig
          if (für kontext unwichtige anweisung) {
           $link_neu="<a href="$link[0]/$link[1]/$link[2]/$link[3]/script.php?f=$f&amp;t=$t" target=_blank]$txt[5]</a>";
          }
            /* $zeile neu bauen */
            $zeile = $txt[1].$link_neu.$txt[6];
          }

          /* $zeile zur Kontrolle ausgeben */
          print "<br>".nl2br($zeile);

          ----------------------- schnipp -----------------------------------

          Problem hierbei ist nicht nur, daß ich den Regex gar nciht kapiere, sondern auch, daß es in einer Endlosschleife endet, klarerweise.
          Wenn ich die < und > testhalber in [ und ] umwandel, funktioniert es tadellos.

          Trotzdem ist mir der Code von EisFux lieber, weil ich ihn eher verstehe.

          Grüße, Gerd

          1. Hier ein umgesetzter Originallink:

            <A HREF="http://www.domain.de/verz/uverz1/uverz1a/datei.html" TARGET=_blank>Linktext</A> (rauskopiert aus $haystack, daher noch die Backshlashes.

            Nicht gerade das, was ich unter HTML verstehe ... ;-)

              
            preg_match_all(  
              '/\<a.+?href=([\"\'])?([^\1]*?)\1[^>]*>(.*?)\<\/a\>/i', //\<\/a\>/is',  
              $haystack,  
              $rx_matches  
            );  
            print_r($rx_matches);  
            
            

            Das lief zumindest bei mir, mit solchen Links, wie von dir angegeben ...
            Der PCRE ist sogar 9 Zeichen kürzer als der hier. ;-)
            Kam nur leider zu spät ...

            MffG
            EisFuX

            --
            ... Suchmaschinen-Blog ...