¿Como funciona?
Echa un vistazo a la teoría de autómatas
En resumen, cada expresión regular tiene un autómata finito equivalente y puede compilarse y optimizarse para un autómata finito. Los algoritmos involucrados se pueden encontrar en muchos libros de compilación. Estos algoritmos son utilizados por programas unix como awk y grep.
Sin embargo, la mayoría de los lenguajes de programación modernos (Perl, Python, Ruby, Java (y lenguajes basados en JVM), C #) no utilizan este enfoque. Utilizan un enfoque de retroceso recursivo, que compila una expresión regular en un árbol o una secuencia de construcciones que representan varios subconjuntos de la expresión regular. La mayoría de las sintaxis modernas de "expresión regular" ofrecen referencias de retroceso que están fuera del grupo de lenguajes regulares (no tienen representación en autómatas finitos), que son trivialmente implementables en el enfoque de retroceso recursivo.
La optimización generalmente produce una máquina de estado más eficiente. Por ejemplo: considere aaaab | aaaac | aaaad, un programador normal puede obtener la implementación de búsqueda simple pero menos eficiente (comparando tres cadenas por separado) en diez minutos; pero al darse cuenta de que es equivalente a aaaa [bcd], se puede hacer una mejor búsqueda al buscar las primeras cuatro 'a' y luego probar el quinto carácter contra [b, c, d]. El proceso de optimización fue uno de mis trabajos de compilación en casa hace muchos años, así que supongo que también está en la mayoría de los motores modernos de expresión regular.
Por otro lado, las máquinas de estado tienen alguna ventaja cuando aceptan cadenas porque usan más espacio en comparación con una "implementación trivial". Considere un programa para eliminar las comillas en cadenas SQL, es decir: 1) comienza y termina con comillas simples; 2) las comillas simples se escapan por dos comillas simples consecutivas. Entonces: la entrada ['a' ''] debería producir la salida [a ']. Con una máquina de estados, las comillas simples consecutivas son manejadas por dos estados. Estos dos estados tienen el propósito de recordar el historial de entrada de modo que cada carácter de entrada se procese exactamente una sola vez, como se ilustra a continuación:
...
S1->'->S2
S1->*->S1, output *, * can be any other character
S2->'->S1, output '
S2->*->END, end the current string
Entonces, en mi opinión, la expresión regular puede ser más lenta en algunos casos triviales, pero generalmente más rápida que un algoritmo de búsqueda diseñado manualmente, dado el hecho de que la optimización no puede ser realizada de manera confiable por humanos.
(Incluso en casos triviales como buscar una cadena, un motor inteligente puede reconocer la ruta única en el mapa de estado y reducir esa parte a una simple comparación de cadena y evitar la administración de estados).
Un motor particular de un marco / biblioteca puede ser lento porque el motor hace muchas otras cosas que un programador generalmente no necesita. Ejemplo: la clase Regex en .NET crea un grupo de objetos que incluyen Match, Grupos y Capturas.