2010-10-15 15 views
5

Sto utilizzando un'espressione regolare per trovare qualsiasi URL e collegarli di conseguenza. Tuttavia, non voglio collegare alcun URL già collegato, quindi sto usando lookbehind per vedere se l'URL ha un href prima di esso. Questo fallisce perché i quantificatori di lunghezza variabile non sono consentiti in lookahead e lookbehind per PHP.quantificatori negativi di lookbehind e greedy in php

Ecco l'espressione regolare per la partita:

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

Qual è il miglior modo per aggirare questo problema?

EDIT:

devo ancora testarlo, ma penso che il trucco per farlo in un unico regex sta usando espressioni condizionali all'interno della regex, che è supportato da PCRE. Sembrerebbe qualcosa di simile:

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

Il punto chiave è che se il href viene catturato, la partita è subito buttato fuori a causa della condizionale (?(1)^|), che è garantito per non corrispondono. Probabilmente c'è qualcosa di sbagliato in questo. Lo proverò domani.

+4

Um, utilizzare un parser HTML e collegare solo quando si tratta di un nodo di testo? – kennytm

+0

Questa è probabilmente la soluzione migliore. Ero più curioso di vedere se c'era un modo per regolare la regex però. –

+0

+1 bella domanda. – NikiC

risposta

1

ho provato a fare la stessa cosa in senso inverso: garantire che l'URL non termina ">:

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

Ma per me che sembra piuttosto hacky, sono sicuro che si può fare meglio.

Il secondo approccio è più simile al tuo (e quindi è più preciso):

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

Se trovo un href= I (*SKIP)(*FAIL). Ciò significa che salgo nella posizione in cui si trova il motore regex, quando incontra lo (*SKIP).

Ma non è meno hacky e sono sicuro che c'è un'alternativa migliore.

+0

Che dire di ''? =) – stevendesu

+0

@steven_desu: Ecco perché vorrei attenermi alla seconda versione;) – NikiC

0

Trovare "ogni URL che non fa parte di un collegamento" è una logica negativa piuttosto difficile. Potrebbe essere più facile trovare ogni URL, quindi ogni URL che è un collegamento e rimuovere tutti gli ultimi dall'elenco precedente.

Per quanto riguarda la constatazione che URLs sono una parte di un collegamento, prova:

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

ho provato con http://regexpal.com/ per essere sicuri. Cerca prima il <a, quindi consente un numero qualsiasi di parametri, seguito da href, seguito da qualsiasi altro numero di parametri. Se non ha il href, non è un collegamento. Se non è un tag <a>, non è un collegamento. Poiché questo è solo l'elenco di ciò che vogliamo rimuovere dall'altra lista (di URL), ho semplificato la definizione di un URL a [\w\s:/.?+&=]+. Per quanto riguarda la generazione di un elenco di URL, ti consigliamo qualcosa di più intelligente.