luti: regex

Hallo,

das "leidige" Thema reguläre Ausdrücke ... aber ich komme einfach nicht weiter. Ich möchte in einem langen Text (html-Code) die externen Links herausfiltern. Soweit mein Ansatz:

$site = preg_replace('#<a[^<>]*href="http://[^<>]*>(.*)</a>#is', '$1', $site);

Nun funktioniert das nicht bei mehr als einem Link, da im (.*)-Teil keine schließenden Link-Tag abgefangen werden. Daher habe ich etwas in der der Art geschrieben, funktioniert aber leider nicht:

$site = preg_replace('#<a[^<>]*href="http://[^<>]*>[^(</a>)]+</a>#is', '$1', $site);

Was ich also will, ist etwas wie beliebig viele Zeichen außer dem Term "</a>". Wo liegt der Fehler? Wie schreibe ich es richtig?

Dank & Gruß,
luti

  1. das "leidige" Thema reguläre Ausdrücke ... aber ich komme einfach nicht weiter.

    Suche nach den Begriffen greedy und non-greedy.

    mfg Beat

    --
    ><o(((°>           ><o(((°>
       <°)))o><                     ><o(((°>o
    Der Valigator leibt diese Fische
    1. Hallo Beat,

      Suche nach den Begriffen greedy und non-greedy.

      Besten Dank! Das war genau das, was ich suchte.

      Nur noch mal der Vollständigkeit halber die Lösung:

      $site = preg_replace('#<a[^<>]*?href="http://[^<>]*?>(.*?)</a>#is', '$1', $site);

      Dank & Gruß,
      luti

      1. Hallo zusammen,

        Ich hätte noch eine Verständnisfrage dazu. (damit man noch was lernt :-) )

        Nur noch mal der Vollständigkeit halber die Lösung:

        $site = preg_replace('#<a[^<>]*?href="http://[^<>]*?>(.*?)</a>#is', '$1', $site);

        Wenn man von solch einem ganz normalen Link ausgeht:
        <a href="http://www.test.html">Hier entlang</a>

        Was genau bedeutet [^<>]  im Suchmuster nach <a ?

        Das "Dach" ^ ist mir klar. Es bedeutet "suche  am Anfang". Was aber machen die Zeichen <>  ?
        Zwischen dem Anker <a und zwischen "href=" kann ja eigentlich ein beliebiges zeichen auftauchen.
        Könnte man nicht auch;
        <a.*href=

        schreiben?

        vielen Dank und viele Grüße
        hawk

        1. Was genau bedeutet [^<>]  im Suchmuster nach <a ?
          Das "Dach" ^ ist mir klar. Es bedeutet "suche  am Anfang". Was aber machen die Zeichen <>  ?

          Nein. Es bedeutet nicht: Suche am Anfang.
          Gehen deinem Irrtum nach, und recherchiere selbst, was [^$listofchars] bedeuten könnte.
          Falls PHP es dir nicht explizit erklärt, Perl tut es.

          Zwischen dem Anker <a und zwischen "href=" kann ja eigentlich ein beliebiges zeichen auftauchen.

          aber nicht ein < oder ein > wenn es sich um einen aktivierbaren Link handeln soll, wie gefordert.

          Könnte man nicht auch;
          <a.*href=
          schreiben?

          Perl:
          "<a><a <dideldumm> href=" =~ /(<a.*href=)/ and print $1;

          gibt aus <a><a <dideldumm> href=

          Teste doch selbst...

          mfg Beat

          --
          ><o(((°>           ><o(((°>
             <°)))o><                     ><o(((°>o
          Der Valigator leibt diese Fische
          1. Hallo Beat,

            Nein. Es bedeutet nicht: Suche am Anfang.
            Gehen deinem Irrtum nach, und recherchiere selbst, was [^$listofchars] bedeuten könnte.

            ok, war klar ein Irrtum.
            Das ^ hier, bdeutet dann wohl das die Zeichen < > zwischen <a und href nicht vorkommen dürfen.

            [^a] ein beliebiges Zeichen außer „a“ („^“ am Anfang einer Zeichenklasse negiert selbige)

            vielen Dank und viele Grüße
            hawk

        2. Hello,

          Ich hätte noch eine Verständnisfrage dazu. (damit man noch was lernt :-) )

          Nur noch mal der Vollständigkeit halber die Lösung:
          $site = preg_replace('#<a[^<>]*?href="http://[^<>]*?>(.*?)</a>#is', '$1', $site);

          Wenn man von solch einem ganz normalen Link ausgeht:
          <a href="http://www.test.html">Hier entlang</a>

          Was genau bedeutet [^<>]  im Suchmuster nach <a ?

          '               Nicht interpretierender Stringbegrenzer für PHP
          #               Patternbegrenzer für die Reg Ex Engine, relativ frei wählbar
                             er sollte aber im Pattern selber nicht vorkommen
          <a              Diese Zeichen sollen vorkommen
          [^<>]*?         darauf folgen Zeichen einer Zeichenklasse, die sich beliebig oft (*)
                             wiederholen und 'gefräßig' gemacht wurden, also alles einsammeln,
                             wenn das Pattern sonst nicht erfüllt werden kann (?).
                             In der Zeichenklasse sind alle Zeichen vorhanden _außer_ (^) < >.
          href="http://   Diese Zeichen müssen folgen
          [^<>]*?         es folgen wieder die Zeichen einer Zeichenklasse s.o.

          Dieses Zeichen soll folgen

          (.*?)           nun folgt eine Suchgruppe (-> Backreferenz).
                             in der gesuchten (unbekannten) Zeichenfolge dürfen alle Zeichen enthalten
                             sein, beliebig oft und 'gefräßig'
          </a>            diese Zeichen müssen folgen
          #               Ende des Patterns
          i               Die Suche soll Case-Insenitive durchgeführt werden
          s               der Punkt (.) als "ein beliebiges Zeichen" schließt auch Whitespaces, also
                             auch Zeilenumbrüche mit ein.
          '               Ende des PHP-Strings

          Liebe Grüße aus dem schönen Oberharz

          Tom vom Berg

          --
          Nur selber lernen macht schlau
          http://bergpost.annerschbarrich.de
          1. #               Ende des Patterns
            i               Die Suche soll Case-Insenitive durchgeführt werden
            s               der Punkt (.) als "ein beliebiges Zeichen" schließt auch Whitespaces, also
                               auch Zeilenumbrüche mit ein.
            '               Ende des PHP-Strings

            //s steuert, ob auch "\n" gematcht wird.
            anderer Whitespace wird mit "." immer gematcht

            mfg Beat

            --
            ><o(((°>           ><o(((°>
               <°)))o><                     ><o(((°>o
            Der Valigator leibt diese Fische
            1. Hello,

              #               Ende des Patterns
              i               Die Suche soll Case-Insenitive durchgeführt werden
              s               der Punkt (.) als "ein beliebiges Zeichen" schließt auch Whitespaces, also
                                  auch Zeilenumbrüche mit ein.
              '               Ende des PHP-Strings

              //s steuert, ob auch "\n" gematcht wird.
              anderer Whitespace wird mit "." immer gematcht

              Danke für die Richtigstellung :-)

              Was mir selber nur noch nicht ganz klar ist: die greedy-Schaltung durch *?
              Ist die sicher so? Gibt es da nicht eine andere Lösung?

              Liebe Grüße aus dem schönen Oberharz

              Tom vom Berg

              --
              Nur selber lernen macht schlau
              http://bergpost.annerschbarrich.de
          2. Hallo Tom,

            ganz herzlichen Dank für die tolle Erklärung.

            Nur nochmals zum Verständnis.
            Im Ausgangsposting ging es dem Autor ja darum das auch mehrere Links gefunden werden sollen. Der ursprüngliche Match

            '#<a[^<>]*href="http://[^<>]*>(.*)</a>#is'

            war gierig weil er von <a bis zum schließenden </a>  alles als ein Suchmuster gefunden hatte.

            Der Modus "s" bedeutet doch Singlemodus. Damit das Muster NICHT gierig ist, wurde dann einfach das "?" verwendet ?

            '#<a[^<>]*?href="http://[^<>]*?>(.*?)</a>#is'

            vielen Dank und viele Grüße
            hawk

            1. Hello,

              ganz herzlichen Dank für die tolle Erklärung.

              Bitte, gerne geschehen. Aber beachte auch die Richtigstellung von Beat zum Modifier s.

              Nur nochmals zum Verständnis.
              Im Ausgangsposting ging es dem Autor ja darum das auch mehrere Links gefunden werden sollen. Der ursprüngliche Match

              '#<a[^<>]*href="http://[^<>]*>(.*)</a>#is'

              war gierig weil er von <a bis zum schließenden </a>  alles als ein Suchmuster gefunden hatte.

              Er war an den entscheidenen Stellen nicht gierig genug.

              Der Modus "s" bedeutet doch Singlemodus. Damit das Muster NICHT gierig ist, wurde dann einfach das "?" verwendet ?

              Nee, siehe Beats Einwand. Der Modifier s beduetet, das der Punkt auch einen Zeilenumbruch matcht, also über das Zeilenende hinaus gesucht werden darf/soll.

              Liebe Grüße aus dem schönen Oberharz

              Tom vom Berg

              --
              Nur selber lernen macht schlau
              http://bergpost.annerschbarrich.de
              1. Hello,

                Er war an den entscheidenen Stellen nicht gierig genug.

                oder doch besser anders herum? Ich sag ja, geht das nicht anders?

                http://de.php.net/manual/en/regexp.reference.php

                However, if a quantifier is followed by a question mark, then it ceases to be greedy, and instead matches the minimum number of times possible, so the pattern /\.*?\/  does the right thing with the C comments. The meaning of the various quantifiers is not otherwise changed, just the preferred number of matches. Do not confuse this use of question mark with its use as a quantifier in its own right. Because it has two uses, it can sometimes appear doubled, as in \d??\d  which matches one digit by preference, but can match two if that is the only way the rest of the pattern matches.

                Ich hätte den Modifier U benutzt
                http://de.php.net/manual/en/reference.pcre.pattern.modifiers.php

                DANN macht das ? den Quantifier gierig...

                *tztz*

                Liebe Grüße aus dem schönen Oberharz

                Tom vom Berg

                --
                Nur selber lernen macht schlau
                http://bergpost.annerschbarrich.de
  2. Hi,

    ergänzend zu Beats Antwort:

    $site = preg_replace('#...[^(</a>)]...#is', '$1', $site);

    Diese Regular Expression ist identisch zu '#...[^a/<>()]...#is'. Beschäftige Dich mit Zeichenklassen.

    Cheatah

    --
    X-Self-Code: sh:( fo:} ch:~ rl:| br:> n4:& ie:% mo:) va:) de:] zu:) fl:{ ss:) ls:~ js:|
    X-Self-Code-Url: http://emmanuel.dammerer.at/selfcode.html
    X-Will-Answer-Email: No
    X-Please-Search-Archive-First: Absolutely Yes
    1. Hallo Cheatah,

      Diese Regular Expression ist identisch zu '#...[^a/<>()]...#is'. Beschäftige Dich mit Zeichenklassen.

      ja, mir war irgendwie schon klar, dass das so nicht ganz richtig ist ;)

      Dank & Gruß,
      luti