Reguläre Ausdrücke - String ausschließen
AndreR
- php
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!
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
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.
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
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
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
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
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
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
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
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
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
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
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
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