¿Cómo funcionan realmente las expresiones regulares?

30

Digamos que tiene un documento con un ensayo escrito. Desea analizar este ensayo para seleccionar solo ciertas palabras. Guay.

¿Está usando una expresión regular más rápido que analizar el archivo línea por línea y palabra por palabra buscando una coincidencia? Si es así, ¿cómo funciona? ¿Cómo puedes ir más rápido que mirar cada palabra?

holgazanear
fuente
55
¿Asume (lo que implica evidencia cero) que una expresión regular será más rápida pero no sabe por qué? Tal vez deberías reconsiderar tu suposición entonces.
pdr
3
así, la suposición. si tuviera evidencia, no sería una, ¿verdad?
lazeR
44
Ese no es el punto. El punto es lo que lo llevó a esa suposición ... No necesita evidencia para sus preguntas, pero sí necesita razonamiento para sus suposiciones.
Yannis
1
err, no todos los caracteres de la cadena de entrada simplemente mueven una máquina de estado al siguiente estado No veo cómo alguien puede conseguir que la operación lenta ...
TP1
2
No estoy seguro de que sea más rápido, pero mi razón principal para usar expresiones regulares se debe a la elegancia de los patrones de coincidencia complejos, simplemente no encontrará una mejor manera de articularlo en un entorno de codificación.
Mantorok

Respuestas:

47

¿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.

Codismo
fuente
2
Yo no podría haberlo dicho mejor. Lo único que agregaría: las expresiones regulares también pueden compensar a los programadores perezosos. En el ejemplo que usted ha mencionado aaaab|aaaac|aaaadvs aaaa[bcd]. Vale la pena declarar explícitamente que los dos son matemáticamente equivalentes y producen el mismo DFA, lo que les da a los programadores más libertad para representar una expresión regular de una manera que tenga sentido (no es una práctica común, pero ... ya sabes). ..
riwalk
Gracias, esto en realidad tenía sentido gracias a la clase de autómatas que tomé
lazeR
¿Es este un ejemplo de un problema trivial donde la expresión regular es exagerada ?: stackoverflow.com/questions/18955099/…
Menelaos Bakopoulos
17

Las expresiones regulares solo se ven rápido porque tienes computadoras rápidas.

En la década de 1980, cuando 1 MIPS era una computadora rápida, las expresiones regulares eran un área bastante grande de preocupación, preocupación e investigación porque eran lentas, feas y computacionales. El desarrollo inteligente de algoritmos siguió y ayudó, pero a todos los efectos prácticos en estos días se está viendo el milagro de las máquinas rápidas que se están desmoronando.

rápidamente_ahora
fuente
2
Si solo está buscando una sola palabra, ambos métodos son iguales (o regexp es un poco más lento). Pero dada una expresión compleja (y un texto de un tamaño razonablemente grande), la expresión regular probablemente será más rápida que una búsqueda simple (suponiendo que escriba la búsqueda simple simplemente (siempre puede escribir una búsqueda compleja que sea tan rápida)). Ahora, si el clima es significativo, es una pregunta demasiado general y tendrá que analizarla caso por caso.
Martin York
3
-1. La teoría de la expresión regular se remonta a los años 50 y fue instrumental en la creación de analizadores léxicos (y, por extensión, compiladores). Crean máquinas de estado muy eficientes que (probablemente) usan la menor cantidad de estados posible. Las máquinas de estado resultantes pueden combinar patrones complejos mucho más rápido que cualquier cosa que pueda escribir a mano. Se ven rápido porque son rápidos.
Riwalk
Podría haber perdido un poco mi punto. Pueden ser "rápidos", pero eso es todo relativo, todavía hay mucho trabajo por hacer. Algunas de las otras respuestas aquí también tienen lectura.
rápidamente_ahora
¿Es esta respuesta relevante a la pregunta? y como 13 votos a favor?
Sadanand
7

¿Por qué crees que son más rápidos que buscar el documento?

Hay algunos trucos que puedes hacer, por ejemplo. si está buscando una palabra de 10 letras que comience con A y termine con B, entonces si encuentra una A y el carácter 9 posiciones más adelante no es B, puede omitir algunas. ver algoritmo Knuth – Morris – Pratt

Martin Beckett
fuente
5

¿Qué hace que una expresión regular sea rápida?

En realidad, no lo son. No mucho. Es solo que no son lo suficientemente lentos para que la mayoría de nosotros nos demos cuenta. En los viejos tiempos lentos, era mucho más notable.

Tampoco son la herramienta adecuada para cada trabajo: el martillo .

Torre
fuente
+1 Gracias por recordarme esa obra de arte en particular ...
yannis
5

Las RegEx son comparativamente más rápidas que el código que podría escribir, porque la mayoría de las bibliotecas son el resultado de que muchos desarrolladores pasan muchos años optimizándolas para obtener el último rendimiento posible. Es difícil para un solo individuo duplicar eso en su propio código de búsqueda.

Gran maestro B
fuente
44
s / chirrido / apretar /?
Péter Török
4

Tu premisa básica es incorrecta.

Las expresiones regulares no siempre son más rápidas que una simple búsqueda. Todo depende del contexto. Depende de la complejidad de la expresión, la longitud del documento que se busca y una gran cantidad de factores.

Lo que sucede es que la expresión regular se compilará en un analizador simple (que lleva tiempo). Por lo tanto, si el documento es pequeño, este tiempo adicional superará cualquier ventaja. Además, si la expresión es simple, entonces la expresión regular no le dará ninguna ventaja.

Si la expresión es compleja y el documento es lo suficientemente grande, puede obtener algún beneficio. Si esto es lo suficientemente significativo como para considerar que las expresiones regulares son más rápidas dependerá en gran medida del esfuerzo que desee poner en la búsqueda (también las expresiones regulares pueden tener algunas optimizaciones que una biblioteca podría proporcionar que no habría pensado en usted).

Lo que estoy tratando de decir es que no hay una respuesta generalizada y general. Si tenía una expresión específica (y un tamaño de documento conocido), entonces podría decir derivar una respuesta sí / no de si la expresión será más rápida que una simple búsqueda (y por qué).

La verdadera ventaja de las expresiones regulares es que una vez que comprende cómo escribirlas, la capacidad de expresar una búsqueda compleja de manera concisa. Debido a que es una forma generalizada, puede crear herramientas que permitan búsquedas de una manera útil en el caso general; Por lo general, es al menos tan rápido como una simple búsqueda (en documentos de tamaño mínimo; en documentos más pequeños que esto no importaría, ya que incluso si es más lento, sigue siendo lo suficientemente rápido).

Martin York
fuente
1

Es plausible que en algunos lenguajes de alto nivel (quizás javascript), el uso de una biblioteca de expresiones regulares implementada en un lenguaje de bajo nivel (quizás C) sea más rápido que escribir lógica de analizador sintáctico en el lenguaje de alto nivel.

Plausible: no tengo idea de si este es realmente el caso.

Steve Bennett
fuente
¡Buena esa! Eso es algo que yo también he considerado. Pero con los procesadores actuales mucho más rápidos que sus predecesores, puedo decir con seguridad que si escribe código de manera eficiente, rara vez podrá distinguir la diferencia. En realidad, en general, no soy realmente gaga sobre la hipótesis más rápida de la expresión regular. ;-)
usuario3833732