Ciertos elementos que pueden aparecer en patrones son más eficientes que otros. Es más eficiente usar una clase de caracteres como [aeiou] que un conjunto de alternativas como (a|e|i|o|u). En general, la construcción más simple que proporciona el comportamiento requerido suele ser la más eficiente. El libro de Jeffrey Friedl contiene mucha discusión sobre cómo optimizar expresiones regulares para un rendimiento eficiente.
Cuando un patrón comienza con .* y la opción PCRE_DOTALL está
establecida, el patrón está implícitamente anclado por PCRE, ya que
solo puede coincidir al inicio de una cadena de sujeto. Sin embargo, si
PCRE_DOTALL no está establecida, PCRE no puede hacer esta optimización,
porque el metacarácter . no coincide entonces con un salto de línea,
y si la cadena de sujeto contiene saltos de línea, el patrón puede
coincidir desde el carácter inmediatamente después de uno de ellos
en lugar de desde el principio. Por ejemplo, el patrón
(.*) second
coincide con la cadena de sujeto "first\nand second" (donde \n representa
un carácter de nueva línea) con la primera subcadena capturada siendo
"and". Para hacer esto, PCRE tiene que volver a intentar la coincidencia
comenzando después de cada salto de línea en el sujeto.
Si está utilizando un patrón como este con cadenas de sujeto que no contienen saltos de línea, el mejor rendimiento se obtiene estableciendo PCRE_DOTALL, o comenzando el patrón con ^.* para indicar anclaje explícito. Esto ahorra a PCRE tener que escanear a lo largo del sujeto buscando un salto de línea para reiniciar.
Tenga cuidado con los patrones que contienen repeticiones indefinidas anidadas.
Estos pueden tardar mucho tiempo en ejecutarse cuando se aplican a una cadena
que no coincide. Considere el fragmento de patrón
(a+)*
Esto puede coincidir con "aaaa" de 33 maneras diferentes, y este número aumenta muy rápidamente a medida que la cadena se alarga. (La repetición * puede coincidir 0, 1, 2, 3 o 4 veces, y para cada uno de esos casos excepto 0, las repeticiones + pueden coincidir con diferentes números de veces.) Cuando el resto del patrón es tal que toda la coincidencia va a fallar, PCRE en principio tiene que probar cada variación posible, y esto puede tomar un tiempo extremadamente largo.
Una optimización atrapa algunos de los casos más simples como
(a+)*b
donde un carácter literal sigue. Antes de embarcarse en el
procedimiento de coincidencia estándar, PCRE verifica que hay una "b"
más adelante en el sujeto, y si no la hay, falla la coincidencia inmediatamente. Sin embargo, cuando no hay un carácter literal siguiente, esta optimización no puede usarse. Puede ver la diferencia comparando el comportamiento de
(a+)*\d
con el patrón anterior. El primero da un fallo casi
instantáneamente cuando se aplica a una línea completa de caracteres "a",
mientras que el segundo tarda un tiempo apreciable con cadenas
más largas que unas 20 caracteres.