¿Cuándo NO debe usar expresiones regulares? [cerrado]

50

Las expresiones regulares son una herramienta poderosa en el arsenal del programador, pero hay algunos casos en que no son la mejor opción, o incluso son dañinas.

El ejemplo simple # 1 es analizar HTML con regexp , un camino conocido hacia numerosos errores. Probablemente, esto también se atribuye al análisis en general.

Pero, ¿hay otras áreas claramente prohibidas para las expresiones regulares?


ps: " La pregunta que haces parece subjetiva y es probable que se cierre ". Por lo tanto, quiero enfatizar que estoy interesado en ejemplos en los que se sabe que el uso de expresiones regulares causa problemas.

c69
fuente
99
Analizar HTML con regexp no es solo "un camino conocido hacia numerosos errores". En realidad es imposible .
Kramii reinstala a Monica el
19
No solo es imposible, también conduce a la locura y la condenación eterna
Martin Wickman
3
@ Jörg: Regexp es solo una abreviatura de expresión regular.
Joren
3
@ Jörg: Es muy cierto que existe una gran diferencia entre las expresiones regulares en matemáticas y sus implementaciones en bibliotecas de software. También es cierto que la mayoría de las bibliotecas de expresiones regulares tienen extensiones que las colocan mucho más allá de aceptar simplemente lenguajes regulares, y que llamarlas expresiones regulares no siempre es tan apropiado. Estoy de acuerdo con usted en que hay dos conceptos diferentes. Pero tienen el mismo nombre; regexp sigue siendo solo una abreviatura, no un término en sí mismo. Muchos de estos ejemplos en este sitio usan el término completo para las bibliotecas de software.
Joren
2
@ Jörg: estas son semánticas. Si bien puede ser una buena idea llamar a estos patrones con diferentes nombres (aunque solo sea para evitar la falacia de "expresiones regulares son para lenguajes regulares"), "regexp" / "expresiones regulares" no es un intento muy bueno, y solo conduce a confusión adicional
Kobi

Respuestas:

60

No uses expresiones regulares:

  • Cuando hay analizadores.

Esto no se limita al HTML . Un XML válido simple no se puede analizar razonablemente con una expresión regular, incluso si conoce el esquema y sabe que nunca cambiará.

No intente, por ejemplo, analizar el código fuente de C # . Analízalo en su lugar, para obtener una estructura de árbol significativa o las fichas.

  • En general, cuando tienes mejores herramientas para hacer tu trabajo.

¿Qué sucede si debe buscar una letra, tanto pequeña como mayúscula? Si te encantan las expresiones regulares, las usarás. ¿Pero no es más fácil / rápido / legible usar dos búsquedas, una tras otra? Es probable que en la mayoría de los idiomas logre un mejor rendimiento y haga que su código sea más legible.

Por ejemplo, el código de muestra en la respuesta de Ingo es un buen ejemplo cuando no debe usar expresiones regulares. Solo busca fooy luego bar.

  • Al analizar la escritura humana.

Un buen ejemplo es un filtro de obscenidad. No solo es una mala idea en general implementarlo, sino que puede sentirse tentado a hacerlo usando expresiones regulares, y lo hará mal. Hay muchas formas en que un humano puede escribir una palabra, un número, una oración y será entendido por otro humano, pero no su expresión regular. Entonces, en lugar de captar una verdadera obscenidad, su expresión regular pasará su tiempo lastimando a otros usuarios.

  • Al validar algunos tipos de datos.

Por ejemplo, no valide una dirección de correo electrónico a través de una expresión regular. En la mayoría de los casos, lo harás mal. En un caso raro, lo hará bien y terminará con un horror de codificación de 6 343 caracteres de longitud .

Sin las herramientas adecuadas, cometerás errores. Y los notarás en el último momento, o tal vez nunca. Si no le importa el código limpio, escribirá una cadena de veinte líneas sin comentarios, sin espacios, sin líneas nuevas.

  • Cuándo se leerá su código. Y luego leer una y otra vez, una y otra vez, cada vez por diferentes desarrolladores.

En serio, si tomo su código y debo revisarlo o modificarlo, no quiero pasar una semana tratando de entender una cadena de veinte líneas con muchos símbolos.

Arseni Mourzenko
fuente
99
"En serio, si tomo su código y debo revisarlo o modificarlo, no quiero pasar una semana tratando de entender una cadena de veinte líneas con muchos símbolos". +1!
funkybro
1
Esta es una respuesta mucho mejor que su hermanastra en el desbordamiento de pila: stackoverflow.com/questions/7553722/…
Kobi
1
Si está usando Perl / PCRE (y probablemente también los otros sabores modernos de (?(DEFINE))expresiones regulares ), lea sobre subrutinas, denominadas grupos de captura y aserciones;) Puede escribir expresiones regulares muy limpias usando esas y, en realidad, cuando las use, escribirá gramáticas que son muy similar a lo que escribirías en yacc o similar;)
NikiC
2
El uso de expresiones regulares para analizar palabras en la lista negra es un error clbuttic.
Dan Ray
No hay ninguna razón en el mundo para evitar lanzar una expresión regular en una cadena como "<a href='foo'>stuff</a>". Las expresiones regulares modernas no tienen problemas con esto.
tchrist
18

Lo más importante: cuando el idioma que está analizando no es un idioma normal .

HTML no es un lenguaje normal y no es posible analizarlo con una expresión regular (no solo es difícil o es un camino hacia un código con errores).

Matteo
fuente
44
¡Incorrecto! Si está utilizando alguno de los sabores modernos de expresiones regulares (Perl, PCRE, Java, .NET, ...), puede hacer recursiones y afirmaciones y, por lo tanto, puede analizar también coincidencias con gramáticas libres de contexto y sensibles al contexto.
NikiC
99
@NikiC. No esta mal. Los "sabores de expresiones regulares modernas" no son expresiones regulares (que se pueden usar para analizar lenguajes regulares, de ahí el nombre). Estoy de acuerdo en que con PRE puede hacer más, pero no los llamaría simplemente "expresiones regulares" (como en la pregunta original).
Matteo
1
Las expresiones regulares modernas están tan lejos de lo que le enseñaron a su abuela que las expresiones regulares podrían hacer que su consejo sea irrelevante. E incluso las expresiones regulares primitivas pueden manejar la mayoría de los pequeños fragmentos de HTML. Esta prohibición general es ridícula y poco realista. Las expresiones regulares se hicieron para este tipo de cosas. Y sí, sé de lo que estoy hablando .
tchrist
12

En stackoverflow, a menudo se ven personas que solicitan expresiones regulares que descubren si una cadena dada no contiene esto o aquello. Esto es, en mi humilde opinión, invirtiendo el propósito de la expresión regular. Incluso si existe una solución (empleando aserciones negativas de retrospectiva o cosas por el estilo), a menudo es mucho mejor usar la expresión regular para lo que fue hecha y manejar el caso negativo con la lógica del programa.

Ejemplo:

# bad
if (/complicated regex that assures the string does NOT conatin foo|bar/) {
    # do something
}

# appropriate
if (/foo|bar/) {
    # error handling
} else {
    # do something
}
Ingo
fuente
1
+1: Algunas veces, he evitado codificarme en una esquina con expresiones regulares deteniéndome y preguntándome "Bien, ¿qué estoy tratando específicamente de hacer coincidir?" en lugar de "¿Qué estoy tratando de evitar?"
5

Dos casos:

Cuando hay una manera más fácil

  • La mayoría de los idiomas proporcionan una función simple como INSTR para determinar si una cadena es un subconjunto de otra. Si eso es lo que quieres hacer, usa la función más simple. No escriba su propia expresión regular.

  • Si hay una biblioteca disponible para realizar una manipulación compleja de cadenas, úsela en lugar de escribir su propia expresión regular.

Cuando las expresiones regulares no son lo suficientemente potentes

  • Si necesita un analizador, use un analizador.
Kramii reinstala a Monica
fuente
0

Las expresiones regulares no pueden identificar estructuras recursivas . Esta es la limitación fundamental.

Tome JSON: es un formato bastante simple, pero dado que un objeto puede contener otros objetos como valores de miembros (arbitrariamente profundos), la sintaxis es recursiva y no puede ser analizada por una expresión regular. Por otro lado, CSV puede ser analizado por expresiones regulares, ya que no contiene ninguna estructura recursiva.

En pocas palabras, las expresiones regulares no permiten que el patrón se refiera a sí mismo. No puede decir: en este punto de la sintaxis coincide con todo el patrón nuevamente. Para decirlo de otra manera, las expresiones regulares solo coinciden linealmente, no contiene una pila que le permita realizar un seguimiento de cuán profundo es un patrón anidado.

Tenga en cuenta que no tiene nada que ver con lo complejo o complicado que es el formato de lo contrario. Las expresiones S son realmente muy simples, pero no se pueden analizar con una expresión regular. CSS2, por otro lado, es un lenguaje bastante complejo, pero no contiene estructuras recursivas y, por lo tanto, se puede analizar con una expresión regular. (Aunque esto no es cierto para CSS3 debido a las expresiones CSS, que tienen una sintaxis recursiva).

Por lo tanto, no es porque sea feo o complejo o propenso a errores para analizar HTML usando solo expresiones regulares. Es que simplemente no es posible .

Si necesita analizar un formato que contiene estructuras recursivas, debe al menos complementar el uso de expresiones regulares con una pila para realizar un seguimiento del nivel de las estructuras recursivas. Esto es típicamente cómo funciona un analizador sintáctico. Las expresiones regulares se usan para reconocer las partes "lineales", mientras que el código personalizado fuera de la expresión regular se usa para realizar un seguimiento de las estructuras anidadas.

Por lo general, el análisis como este se divide en fases separadas. La tokenización es la primera fase donde se usan expresiones regulares para dividir la entrada en una secuencia de "tokens" como palabras, puntuación, corchetes, etc. El análisis es la siguiente fase donde estos tokens se analizan en una estructura jerárquica, un árbol de sintaxis.

Entonces, cuando escuche que HTML o C # no se pueden analizar mediante expresiones regulares, tenga en cuenta que las expresiones regulares siguen siendo una parte crítica de los analizadores. Simplemente no puede analizar dicho lenguaje utilizando solo expresiones regulares y ningún código auxiliar.

JacquesB
fuente