2009-03-25 12 views
6

Ho una matrice piena di schemi che ho bisogno di abbinare. Un modo per farlo, diverso da un ciclo for()? Sto cercando di farlo nel modo meno intenso della CPU, dato che ne farò decine ogni minuto.Come si esegue un preg_match in cui il pattern è un array, in php?

L'esempio del mondo reale consiste nel creare un controllo dello stato dei collegamenti, che controllerà i collegamenti a vari siti di video online, per garantire che i video siano ancora in diretta. Ogni dominio ha diverse "parole chiave morte", se si trovano nel codice HTML di una pagina, il che significa che il file è stato cancellato. Questi sono memorizzati nella matrice. Ho bisogno di abbinare il contenuto della matrice, contro l'output html della pagina.

risposta

20

Prima di tutto, se si sta solo facendo letteralmente decine ogni minuto, quindi io non mi preoccuperei terribilmente per le prestazioni in questo caso. Queste partite sono piuttosto veloce, e non credo che si sta andando ad avere un problema di prestazioni scorrendo l'array modelli e chiamando preg_match separatamente come questo:

$matches = false; 
foreach ($pattern_array as $pattern) 
{ 
    if (preg_match($pattern, $page)) 
    { 
    $matches = true; 
    } 
} 

È possibile infatti combinare tutti i modelli in una sola utilizzando l'operatore or come suggeriscono alcune persone, ma non limitarsi a schiacciarle insieme con un |. Questo si interromperà se uno qualsiasi dei tuoi modelli contiene l'operatore o.

lo consiglio almeno raggruppare i vostri modelli usando le parentesi come:

foreach ($patterns as $pattern) 
{ 
    $grouped_patterns[] = "(" . $pattern . ")"; 
} 
$master_pattern = implode($grouped_patterns, "|"); 

Ma ... io non sono davvero sicuro se questo finisce per essere più veloce. Qualcosa da fare deve passarci sopra, che si tratti del preg_match o del PHP. Se dovessi indovinare, immagino che le singole corrispondenze siano tanto più facili da leggere e da mantenere.

Infine, se la prestazione è ciò che stai cercando qui, penso che la cosa più importante da fare sia estrarre le corrispondenze non regex in un semplice controllo "stringa contiene". Immagino che alcuni dei tuoi assegni debbano essere semplici controlli sulle stringhe, come cercare di vedere se "Questo sito è chiuso" è nella pagina.

Così facendo questo:

foreach ($strings_to_match as $string_to_match) 
{ 
    if (strpos($page, $string_to_match) !== false)) 
    { 
    // etc. 
    break; 
    } 
} 
foreach ($pattern_array as $pattern) 
{ 
    if (preg_match($pattern, $page)) 
    { 
    // etc. 
    break; 
    } 
} 

ed evitare il maggior numero preg_match() possibile è destinata probabilmente ad essere il vostro migliore guadagno. strpos() è un lotto più veloce di preg_match().

+4

Per motivi di googler, considera di utilizzare break (http://www.php.net/manual/en/control-structures.break.php) per uscire dal ciclo foreach una volta trovata una corrispondenza! –

+2

Credo che dovrebbe essere questo: foreach ($ pattern_array as $ pattern), almeno nella mia versione di PHP – hellomynameisjoel

+1

Va bene ragazzi ... modificato per indirizzare i vostri commenti. – danieltalsky

0

Se si dispone di una serie di motivi, ciò che si può fare è concatenarli in una singola espressione regolare e abbinarli. Non c'è bisogno di un ciclo.

1

Se si sta semplicemente cercando la presenza di una stringa in un'altra stringa, utilizzare strpos in quanto è più veloce.

Altrimenti, si potrebbe semplicemente scorrere l'array di schemi, chiamando ogni volta preg_match.

10
// assuming you have something like this 
$patterns = array('a','b','\w'); 

// converts the array into a regex friendly or list 
$patterns_flattened = implode('|', $patterns); 

if (preg_match('/'. $patterns_flattened .'/', $string, $matches)) 
{ 
} 

// PS: that's off the top of my head, I didn't check it in a code editor 
+1

Funzionerà senza parentesi/parentesi intorno ai "motivi"? – JedatKinports

0

Che ne dici di fare un str_replace() sul codice HTML che si ottiene utilizzando l'array e quindi verificare se l'originale HTML è uguale all'originale?Questo sarebbe molto veloce:

$sites = array(
     'you_tube' => array('dead', 'moved'), 
     ... 
); 
foreach ($sites as $site => $deadArray) { 
    // get $html 
    if ($html == str_replace($deadArray, '', $html)) { 
     // video is live 
    } 
} 
+0

str_replace non funziona se si desidera una corrispondenza esatta –

2

Se i modelli non contengono molti spazi bianchi, un'altra opzione sarebbe quella di rifuggire gli array e utilizzare il modificatore /x. Ora il vostro elenco di espressioni regolari sarebbe simile a questa:

$regex = "/ 
pattern1| # search for occurences of 'pattern1' 
pa..ern2| # wildcard search for occurences of 'pa..ern2' 
pat[ ]tern| # search for 'pat tern', whitespace is escaped 
mypat  # Note that the last pattern does NOT have a pipe char 
/x"; 

con il modificatore /x, spazi è completamente ignorato, tranne quando in una classe di caratteri o preceduto da una barra rovesciata. Sono ammessi anche commenti come sopra.

Ciò eviterebbe il loop attraverso la matrice.