2010-10-15 12 views
5

Ich benutze eine Regex, um alle URLs zu finden und sie entsprechend zu verknüpfen. Ich möchte jedoch keine URLs verknüpfen, die bereits verknüpft sind. Daher verwende ich Lookbehind, um zu sehen, ob die URL eine href hat. Dies schlägt jedoch fehl, da Quantifizierer variabler Länge in Lookahead und Lookbehind für PHP nicht erlaubt sind.negative Lookbehind und gierige Quantifikatoren in PHP

Hier ist die regex für das Spiel:

/\b(?<!href\s*=\s*[\'\"])((?:http:\/\/|www\.)\S*?)(?=\s|$)/i 

Was ist der beste Weg, um dieses Problem?

EDIT:

Ich habe noch zu testen, aber ich denke, der Trick es in einer einzigen Regex zu tun bedingte Ausdrücke innerhalb der Regex verwendet, die von PCRE unterstützt wird. Es würde wie folgt aussehen:

/(href\s*=\s*[\'\"])?(?(1)^|)((?:http:\/\/|www\.)\w[\w\d\.\/]*)(?=\s|$)/i 

Der entscheidende Punkt ist, dass, wenn die href erfasst wird, wird das Spiel sofort aufgrund der bedingten (?(1)^|) hinausgeworfen, die nicht passen garantiert wird. Da ist wahrscheinlich etwas nicht in Ordnung. Ich werde es morgen testen.

+4

Um, verwenden Sie einen HTML-Parser und verknüpfen Sie nur, wenn es ein Textknoten ist? – kennytm

+0

Das ist wahrscheinlich die beste Lösung. Ich war mehr neugierig, ob es eine Möglichkeit gab, die Regex anzupassen. –

+0

+1 nette Frage. – NikiC

Antwort

1

Ich habe versucht, die gleiche Sache andersrum machen: Stellen Sie sicher, dass die URL endet nicht in ">:

/((?:http:\/\/|www\.)(?:[^"\s]|"[^>]|(*FAIL))*?)(?=\s|$)/i 

Aber für mich das ziemlich hacky sieht, ich bin sicher, dass Sie besser machen können.

Mein zweiter Ansatz ist ähnlich wie bei Ihnen (und damit ist präziser):

/href\s*=\s*"[^"]*"(*SKIP)(*FAIL)|((?:http:\/\/|www\.)\S*?)(?=\s|$)/i 

Wenn ich ein href= ich (*SKIP)(*FAIL) finden. Dies bedeutet, dass ich zu der Position springe, an der sich die Regex-Engine befindet, wenn sie auf (*SKIP) trifft.

Aber das ist nicht weniger hacky und ich bin sicher, es gibt eine bessere Alternative.

+0

Was ist mit ''? =) – stevendesu

+0

@steven_desu: Deswegen würde ich bei der zweiten Version bleiben;) – NikiC

0

Suche nach "jeder URL, die nicht Teil eines Links ist" ist ziemlich schwierig negative Logik. Es kann einfacher sein, jede URL zu finden, dann jede URL, die ein Link ist, und jeden der Letzteren aus der vorherigen Liste zu entfernen.

Soweit Feststellung, die sind ein Teil einer Link-URLs, versuchen:

/<a([\s]+[\w="]+)*[\s]+href[\s]*=[\s]*"([\w\s:/.?+&=]+)"([\s]+[\w="]+)*>/i 

Getestet habe ich es mit http://regexpal.com/ sicher zu sein. Es sucht zuerst nach dem <a, dann erlaubt es eine beliebige Anzahl von Parametern, gefolgt von href, gefolgt von einer beliebigen anderen Anzahl von Parametern. Wenn es nicht die href hat, ist es kein Link. Wenn es kein <a> Tag ist, ist es kein Link. Da dies nur die Liste von dem ist, was wir wollen entfernen von der anderen Liste (von URLs), vereinfachte ich die Definition einer URL zu [\w\s:/.?+&=]+. Was das Generieren einer Liste von URLs betrifft, möchten Sie etwas intelligenteres.