2009-03-25 4 views
6

Tengo una matriz llena de patrones que necesito emparejar. ¿Hay alguna manera de hacer eso, que no sea un bucle for()? Estoy tratando de hacerlo de la manera menos intensiva de CPU, ya que voy a hacer docenas de estos cada minuto.¿Cómo se realiza un preg_match donde el patrón es una matriz, en php?

El ejemplo del mundo real es, Im la construcción de un comprobador de estado del enlace, que verificará los enlaces a varios sitios de videos en línea, para garantizar que los videos estén todavía en vivo. Cada dominio tiene varias "palabras clave muertas", si se encuentran en el html de una página, eso significa que el archivo fue eliminado. Estos se almacenan en la matriz. Necesito hacer corresponder el contenido de la matriz con la salida html de la página.

Respuesta

20

En primer lugar, si, literalmente, sólo se está haciendo decenas cada minuto , entonces no me preocupe terriblemente sobre el rendimiento en este caso. Estos partidos son bastante rápido, y no creo que vas a tener un problema de rendimiento por iteración a través de la matriz de patrones y llamando preg_match separado de esta manera:

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

Puede en efecto combinar todos los patrones en uno usando el operador or como algunas personas están sugiriendo, pero no se limite a unirlas con un |. Esto se romperá gravemente si alguno de sus patrones contiene el operador or.

recomendaría al menos agrupar sus patrones de uso de paréntesis como:

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

Pero ... no estoy realmente seguro de si esto termina siendo más rápido. Algo tiene que recorrerlos, ya sea el preg_match o PHP. Si tuviera que adivinar, supongo que las coincidencias individuales serían tan rápidas y fáciles de leer y mantener.

Por último, si el rendimiento es lo que está buscando aquí, creo que lo más importante es retirar las coincidencias que no son de expresiones regulares en una simple comprobación de "cadena contiene". Me imagino que algunos de sus cheques deben ser simples comprobaciones de cadena, como mirar para ver si "Este sitio está cerrado" está en la página.

Así que hacer esto:

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; 
    } 
} 

y evitar el mayor número posible preg_match() es probablemente va a ser su mejor ganancia. strpos() es un lote más rápido que preg_match().

+4

Por el bien del Googler, considere usar break (http://www.php.net/manual/es/control-structures.break.php) para salir del bucle foreach una vez que haya encontrado una coincidencia. –

+2

Creo que esto debería ser: foreach ($ pattern_array as $ pattern), al menos en mi versión de PHP – hellomynameisjoel

+1

Muy bien chicos ... editado para abordar sus comentarios. – danieltalsky

0

Si tiene muchos patrones, lo que puede hacer es concatenarlos en una sola expresión regular y hacer coincidir eso. No hay necesidad de un bucle.

1

Si simplemente buscas la presencia de una cadena en otra cadena, utiliza strpos ya que es más rápido.

De lo contrario, podría iterar sobre la matriz de patrones, llamando a preg_match cada vez.

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

¿Funcionará esto sin paréntesis/corchetes alrededor de los "patrones"? – JedatKinports

0

¿Qué tal si haces un str_replace() en el HTML que obtienes al usar tu matriz y luego verificas si el HTML original es igual al original?Esto sería muy rápido:

$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 no funciona si quieres una coincidencia exacta –

2

Si los patrones no contienen muchos espacios en blanco, otra opción sería la de evitar las matrices y utilizar el modificador /x. Ahora su lista de expresiones regulares se vería así:

$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 el modificador /x, espacios en blanco se ignora por completo, excepto cuando en una clase de caracteres o precedido por una barra invertida. Los comentarios como arriba también están permitidos.

Esto evitaría el bucle a través de la matriz.

Cuestiones relacionadas