AndreR: Reguläre Ausdrücke - String ausschließen

Ich habe mir mit PHP ein kleines Script geschrieben, dass Links aus einem HTML-Dokument filtern kann. Mein Problem ist jetzt, dass ich alle Links ausschließen möchte, die nicht entweder in einem 'a' oder in einem 'area' stehen und außerdem die Anzeige von Links mit Javascript verhindern will, also <a href="javascript: * >. Wie muss ich dazu einen Code erweitern?

<?php  
$source = implode(file($_GET['url']));  
preg_match_all("#<a.*[^>]href=\"(.*)\"#U", $source, $array);  
foreach($array[1] as $value) {  
  echo $value.'<br>';  
}  
?>

Danke schonmal für die Hilfe!

  1. Hello,

    Ich habe mir mit PHP ein kleines Script geschrieben, dass Links aus einem HTML-Dokument filtern kann. Mein Problem ist jetzt, dass ich alle Links ausschließen möchte, die nicht entweder in einem 'a' oder in einem 'area' stehen und außerdem die Anzeige von Links mit Javascript verhindern will, also <a href="javascript: * >. Wie muss ich dazu einen Code erweitern?

    $pattern = "#<(a|area)\s[^>]*href="(?<!javascript:)\s*(.*)".*>#Ui";
                       1                      ./.            2

    Sschau mal, ob das klappt soweit.
    Ich habe gerade leider keine Seite, in der 'JavaScript' drinsteht im Link...

    Das    (?<!   nennt sich negative lookbehind assertion

    und wurd hier neulich nochmal ausführlich von Seth erklärt.
    Es bedeutet, dass die erwähnte Behauptung (Assertion) NICHT vor dem Suchbegriff auftreten darf.
    Sie ist selber _nicht_ Bestandteil der Treffermengen (./.), man kann also auch nicht mit Backreferenz darauf zugreifen. Deine Ergebnisse sammeln sich dann im Array[2]

    Harzliche Grüße vom Berg und Frohe Weihnachtszeit

    Tom

    --

    Nur selber lernen macht schlau
    zweifeln lassen :-)

    1. Danke erstmal, das mit dem area oder a klappt jetzt.

      Ich habe gerade leider keine Seite, in der 'JavaScript' drinsteht im Link...

      Leider tut das noch nicht :(.

      Gibt es eig. Seiten, wo man das lernen kann? Irgendwie habe ich bisher nur Schrott und lückenhafte Seiten gefunden.

      1. Hello,

        Danke erstmal, das mit dem area oder a klappt jetzt.

        Ich habe gerade leider keine Seite, in der 'JavaScript' drinsteht im Link...

        Leider tut das noch nicht :(.

        Hab ich auch gerade festgestellt, weil ich dachte, es wäre nochmal eine gute Gelgenheit zum Üben.

        Ich ahbe auch den "Bananen-Thread" extra nochmal rausgesucht.

        http://forum.de.selfhtml.org/archiv/2007/11/t161925/#m1053426

        Bisher konnte ich nichts finden, dass negative lookbehind assertions in preg_match_all nicht funktionieren sollen, zumal dort auch in der Beschreibung von PHP am Rande darauf bezug genommen wird.
        http://de2.php.net/manual/de/function.preg-match-all.php

        "... weil Suchmuster  Angaben wie zum Beispiel ^, $ oder (?<=x) enthalten kann. ..."

        Da geht es zwar um die Berechnung des Versatzes, aber wieso sollte man eine positive lookbehind assertion als Beispiel nennen, wenn gerade die hier überhaupt nicht funktioniert?

        Kann sein, dass ich das mal wieder vollkommen verkehrt herum sehe...
        Vielleicht guckt ja nioch jemand rein hier, der das Rätsel lösen kann.

        Harzliche Grüße vom Berg und Frohe Weihnachtszeit

        Tom

        --

        Nur selber lernen macht schlau
        zweifeln lassen :-)

    2. Hi,

      href="(?<!javascript:)

      Das kann nicht klappen.

      Das    (?<!   nennt sich negative lookbehind assertion

      Eben. Lookbehind. Hier müßte aber ein lookahead stehen.

      Wenn der Regex-Matcher an der Stelle angekommen ist, an der die lookbehind assertion ist, ist unmittelbar hinter ihm ein Anführungszeichen.
      Also kann an dieser Stelle kein javascript: im lookbehind gefunden werden, da javascript: ja nicht mit " endet.

      und wurd hier neulich nochmal ausführlich von Seth erklärt.

      Offensichtlich nicht ausführlich genug.

      cu,
      Andreas

      --
      Warum nennt sich Andreas hier MudGuard?
      O o ostern ...
      Fachfragen unaufgefordert per E-Mail halte ich für unverschämt und werde entsprechende E-Mails nicht beantworten. Für Fachfragen ist das Forum da.
      1. Hello,

        href="(?<!javascript:)

        Das kann nicht klappen.

        Das    (?<!   nennt sich negative lookbehind assertion

        Eben. Lookbehind. Hier müßte aber ein lookahead stehen.

        Die vorläufige Auflösung des Knotens Das ist in einem anderen Thread gelandet.
        Ich muss nochmal suchen, wo.

        Harzliche Grüße aus
        Sankt Andreasberg
        und Guten Rutsch

        Tom

        --
        Nur selber lernen macht schlau

        1. Hello,

          href="(?<!javascript:)

          Das kann nicht klappen.

          Das    (?<!   nennt sich negative lookbehind assertion

          Eben. Lookbehind. Hier müßte aber ein lookahead stehen.

          Die vorläufige Auflösung des Knotens Das ist in einem anderen Thread gelandet.

          https://forum.selfhtml.org/?t=163975&m=1068690

          Harzliche Grüße aus
          Sankt Andreasberg
          und Guten Rutsch

          Tom

          --
          Nur selber lernen macht schlau

    3. Hi,

      a|area

      Noch eine Anmerkung:

      Funktioniert, ist aber ineffizient.

      a(?:rea)?

      matcht dasselbe, ist aber effizienter.
      (?:) gruppiert, ohne daß der entsprechende Teilstring gemerkt wird (das Merken kostet, sollte also auch nur gemacht werden, wenn's wirklich gebraucht wird).

      cu,
      Andreas

      --
      Warum nennt sich Andreas hier MudGuard?
      O o ostern ...
      Fachfragen unaufgefordert per E-Mail halte ich für unverschämt und werde entsprechende E-Mails nicht beantworten. Für Fachfragen ist das Forum da.
      1. Hello,

        a|area

        Noch eine Anmerkung:

        Funktioniert, ist aber ineffizient.

        a(?:rea)?

        matcht dasselbe, ist aber effizienter.
        (?:) gruppiert, ohne daß der entsprechende Teilstring gemerkt wird (das Merken kostet, sollte also auch nur gemacht werden, wenn's wirklich gebraucht wird).

        Ist es von Relevanz, dass nachher noch eine Backreferenz darauf gerichtet ist?

        Harzliche Grüße aus
        Sankt Andreasberg
        und Guten Rutsch

        Tom

        --
        Nur selber lernen macht schlau

        1. Hi,

          a(?:rea)?

          matcht dasselbe, ist aber effizienter.
          (?:) gruppiert, ohne daß der entsprechende Teilstring gemerkt wird (das Merken kostet, sollte also auch nur gemacht werden, wenn's wirklich gebraucht wird).

          Ist es von Relevanz, dass nachher noch eine Backreferenz darauf gerichtet ist?

          auf das 'rea'? Wohl kaum.
          Die Capturing Klammern, die um das 'a(?:rea)?' bzw. 'a|area' außenrum sind, haben damit nichts zu tun.

          cu,
          Andreas

          --
          Warum nennt sich Andreas hier MudGuard?
          O o ostern ...
          Fachfragen unaufgefordert per E-Mail halte ich für unverschämt und werde entsprechende E-Mails nicht beantworten. Für Fachfragen ist das Forum da.
          1. Hello,

            a(?:rea)?

            matcht dasselbe, ist aber effizienter.
            (?:) gruppiert, ohne daß der entsprechende Teilstring gemerkt wird (das Merken kostet, sollte also auch nur gemacht werden, wenn's wirklich gebraucht wird).

            Ist es von Relevanz, dass nachher noch eine Backreferenz darauf gerichtet ist?

            auf das 'rea'? Wohl kaum.
            Die Capturing Klammern, die um das 'a(?:rea)?' bzw. 'a|area' außenrum sind, haben damit nichts zu tun.

            Na eben!
            Das ?: führt ja auch dazu, dass das Argument _nicht_ in die Ergebnismengen aufgenommen wird.

            Ich hole mal das vorläufige Ergebnis dieser Show aus dem anderen Thread:
            Damit wird das hier zu einem micht klassischem Doppelposting. Sorry, aber es ist ja noch nicht geklärt...

            #----- matcht alle Links MIT Häkchen und ohne JavaScript usw. -----------------------------------

            $pattern1= '#<(a|area)\s*.*href=("|')(?!javascript:|mailto:)(\S*)\2\s*([^>]*)>(.+)</\1>#Ui';

            #------------------------------------------------------------------------------------------------

            #----- matcht alle Links OHNE Häkchen und ohne JavaScript usw. ----------------------------------

            $pattern2= '#<(a|area)\s*.*href=(?!"|'|javascript:|mailto:)([^\s]*?)(?<!"|')\s*([^>]*)>(.+)</\1>#Ui';

            #------------------------------------------------------------------------------------------------

            das (a|area) wird hier benötigt, um nachher auch den Linktext einfangen zu können, nicht nur die url. Und dazu wird eine Backreferenz benutzt. Die ist aber nicht möglich, wenn Du die von Dir vorgeschalgene Variante benutzt.

            Ich habe es bisher nicht geschafft, die beiden Teillösungen einer Gesamtlösung zusammenzuführen.

            Harzliche Grüße aus
            Sankt Andreasberg
            und Guten Rutsch

            Tom

            --
            Nur selber lernen macht schlau

            1. Hi,

              Die Capturing Klammern, die um das 'a(?:rea)?' bzw. 'a|area' außenrum sind, haben damit nichts zu tun.

              Na eben!

              Eben. Das (?:) sorgt dafür, daß keine "Backreferenz" für diese Klammer erzeugt wird.

              Die Capturing Klammern außenrum haben damit, wie erwähnt, nichts zu tun. Sprich: für diese wird selbstverständlich nach wie vor der gesamte vom Inhalt gematchte Teilstring gemerkt.

              Das ?: führt ja auch dazu, dass das Argument _nicht_ in die Ergebnismengen aufgenommen wird.

              Es sorgt dafür, daß für diese Klammer keine eigene Backreferenz erzeugt wird.

              $pattern1= '#<(a|area)\s*.*href=("|')(?!javascript:|mailto:)(\S*)\2\s*([^>]*)>(.+)</\1>#Ui';

              das (a|area) wird hier benötigt, um nachher auch den Linktext einfangen zu können,

              Nein, die wird benötigt, um das schließende Tag zu finden.
              Daß das bei area nicht funktionieren kann, ist Dir aber klar? area ist ein leeres Element.

              Das Ende des Ausdrucks sollte also

              (?:(.+?)</\1>)?

              lauten, sprich: alles nach dem Schließen des Tags bis zum schließenden a-Tag (area kann's ja nicht sein) muß optional sein, da sonst area-Elemente nicht erfaßt werden.

              Dein Ausdruck hat außerdem Probleme mit mehreren Links hintereinander, er ist zu gierig.

              <(a(?:rea)?)\s*[^>]*?href=("|')(?!javascript:|mailto:)(\S*)\2\s*([^>]*)>(?:(.+?)</\1>)?
              sollte einigermaßen funktionieren.

              Ach ja, zum Rumspielen empfehle ich Regex Coach

              Und dazu wird eine Backreferenz benutzt. Die ist aber nicht möglich, wenn Du die von Dir vorgeschalgene Variante benutzt.

              Natürlich funktioniert es mit meiner Variante. Eine Backreferenz auf das rea wird nicht benötigt (eine auf den kompletten tag-Name schon, aber die bleibt ja unberührt).

              cu,
              Andreas

              --
              Warum nennt sich Andreas hier MudGuard?
              O o ostern ...
              Fachfragen unaufgefordert per E-Mail halte ich für unverschämt und werde entsprechende E-Mails nicht beantworten. Für Fachfragen ist das Forum da.
              1. Hello,

                na gut, dann eben noch eine Übungsrunde.

                Ach ja, zum Rumspielen empfehle ich Regex Coach

                Den hatte ich auch schon gefunden, wusste nur nicht, was er taugt.

                Harzliche Grüße aus
                Sankt Andreasberg
                und Guten Rutsch

                Tom

                --
                Nur selber lernen macht schlau

  2. Hello,

    Ich habe mir mit PHP ein kleines Script geschrieben, dass Links aus einem HTML-Dokument filtern kann. Mein Problem ist jetzt, dass ich alle Links ausschließen möchte, die nicht entweder in einem 'a' oder in einem 'area' stehen und außerdem die Anzeige von Links mit Javascript verhindern will, also <a href="javascript: * >. Wie muss ich dazu einen Code erweitern?

    <?php

    $source = file_get_contents($_GET['url']);

    $pattern = "#<(a|area)\s[^>]*href="(?<!javascript:)\s*(.*)".*>#Ui";

    preg_match_all($pattern, $source, $array);

    foreach($array[2] as $key => $value)
      {
        if (strpos(strtolower($value),'javascript:') === 0)
        {
          unset($array[2][$key]);
        }
        else
        {
          echo htmlspechialchars($value).'<br>';
        }
      }

    ## Das Array[2] enthält nur keine Lemente mehr, die mit 'javascript:' anfingen

    ?>

    Als "Reparaturmaßnahme" für die kaputte "negative lookbehind assertion".

    Harzliche Grüße vom Berg und Frohe Weihnachtszeit

    Tom

    --

    Nur selber lernen macht schlau
    zweifeln lassen :-)

  3. Hello Andre,

    es hat mir keine Ruhe gelassen, dass ich das nicht hinbekommen habe.
    Aber nun habe ich eine Lösung, die funktioniert, nur leider widerspricht sie den Regeln.

    Christian Seiler hatte eine wesentliche Anregung dazu gegeben, aber so ganz hat die auch nicht funktioniert. Ich würde es nun nur gerne auch verstehen, warum diese es tut.

    <?php   ### negative_lookahead.php  ###

    if (isset($_GET['url']))
    {
        $source = file_get_contents($_GET['url']);

    $pattern= '#<(a|area)\s*.*(?!href=.?javascript:|href=.?mailto:)href=("|'|)?(\S+)\2\s*([^>]*)>(.+)</\1>#i';

    preg_match_all($pattern, $source, $_hits);

    echo "<pre>\n";
        echo htmlspecialchars(print_r($_hits,1));
        echo "</pre>\n";
    }
    else
    {
        echo "<p>bitte URL angeben: ?url=http://example.com</p>\n";
    }

    ?>

    Harzliche Grüße vom Berg und Frohe Weihnachtszeit

    Tom

    --
    Nur selber lernen macht schlau