Muchos programadores conocen la alegría de generar una expresión regular rápida, en estos días a menudo con la ayuda de algún servicio web, o más tradicionalmente en un mensaje interactivo, o tal vez escribiendo un pequeño script que tiene la expresión regular en desarrollo, y una colección de casos de prueba. . En cualquier caso, el proceso es iterativo y bastante rápido: sigue pirateando la cadena de aspecto críptico hasta que coincida y capture lo que quieres y rechazará lo que no quieres.
Para un caso simple, el resultado podría ser algo como esto, como una expresión regular de Java:
Pattern re = Pattern.compile(
"^\\s*(?:(?:([\\d]+)\\s*:\\s*)?(?:([\\d]+)\\s*:\\s*))?([\\d]+)(?:\\s*[.,]\\s*([0-9]+))?\\s*$"
);
Muchos programadores también conocen el dolor de tener que editar una expresión regular, o simplemente codificar alrededor de una expresión regular en una base de código heredada. Con un poco de edición para dividirlo, la expresión regular anterior todavía es muy fácil de comprender para cualquier persona razonablemente familiarizada con expresiones regulares, y un veterano de expresiones regulares debería ver de inmediato lo que hace (responda al final de la publicación, en caso de que alguien quiera el ejercicio) de resolverlo ellos mismos).
Sin embargo, las cosas no necesitan volverse mucho más complejas para que una expresión regular se convierta realmente en algo de solo escritura, e incluso con documentación diligente (lo que, por supuesto , todo el mundo hace para todas las expresiones regulares complejas que escriben ...), modificar las expresiones regulares se convierte en una tarea desalentadora. También puede ser una tarea muy peligrosa, si regexp no se prueba cuidadosamente en unidades (pero, por supuesto, todos tienen pruebas unitarias exhaustivas para todas sus expresiones regulares complejas, tanto positivas como negativas ...).
Entonces, para resumir, ¿hay una solución / alternativa de escritura-lectura para expresiones regulares sin perder su poder? ¿Cómo se vería la expresión regular anterior con un enfoque alternativo? Cualquier idioma está bien, aunque una solución en varios idiomas sería lo mejor, en la medida en que las expresiones regulares son en varios idiomas.
Y luego, lo que hace la expresión regular anterior es esto: analizar una cadena de números en formato 1:2:3.4
, capturando cada número, donde los espacios están permitidos y solo 3
se requieren.
Respuestas:
Varias personas han mencionado componer desde partes más pequeñas, pero nadie ha proporcionado un ejemplo todavía, así que aquí está el mío:
No es el más legible, pero siento que es más claro que el original.
Además, C # tiene el
@
operador que puede anteponerse a una cadena para indicar que debe tomarse literalmente (sin caracteres de escape), pornumber
lo que sería@"([\d]+)";
fuente
[\\d]+
y[0-9]+
deberían ser justos\\d+
(bueno, algunos pueden encontrar[0-9]+
más legibles). No voy a editar la pregunta, pero es posible que desee corregir esta respuesta.\d
coincidirán con cualquier cosa que se considere un número, incluso en otros sistemas de numeración (chino, árabe, etc.), mientras[0-9]
que solo coincidirán con los dígitos estándar. Sin\\d
embargo, sí estandaricé y lo incluí en eloptionalDecimal
patrón.La clave para documentar la expresión regular es documentarla. Con demasiada frecuencia, las personas arrojan lo que parece ser ruido de línea y lo dejan así.
Dentro de Perl, el
/x
operador al final de la expresión regular suprime los espacios en blanco, lo que permite documentar la expresión regular.La expresión regular anterior se convertiría en:
Sí, consume un poco de espacio en blanco vertical, aunque uno podría acortarlo sin sacrificar demasiada legibilidad.
Mirando esta expresión regular, uno puede ver cómo funciona (y no funciona). En este caso, esta expresión regular coincidirá con la cadena
1
.Se pueden adoptar enfoques similares en otro idioma. La opción de python re.VERBOSE funciona allí.
Perl6 (el ejemplo anterior era para perl5) lleva esto más allá con el concepto de reglas que conduce a estructuras aún más poderosas que el PCRE (proporciona acceso a otras gramáticas (sin contexto y sensibles al contexto) que solo las regulares regulares y extendidas).
En Java (de donde se deriva este ejemplo), se puede usar la concatenación de cadenas para formar la expresión regular.
Es cierto que esto crea muchos más
"
en la cadena, lo que posiblemente genere cierta confusión allí, puede leerse más fácilmente (especialmente con el resaltado de sintaxis en la mayoría de los IDE) y documentarse.La clave es reconocer el poder y la naturaleza de "escribir una vez" en la que a menudo caen las expresiones regulares. Escribir el código para evitar esto defensivamente para que la expresión regular permanezca clara y comprensible es clave. Formateamos el código Java para mayor claridad: las expresiones regulares no son diferentes cuando el lenguaje le da la opción de hacerlo.
fuente
El modo "detallado" que ofrecen algunos idiomas y bibliotecas es una de las respuestas a estas inquietudes. En este modo, el espacio en blanco en la cadena regexp se elimina (por lo que debe usar
\s
) y los comentarios son posibles. Aquí hay un breve ejemplo en Python que admite esto de manera predeterminada:En cualquier idioma que no sea así, implementar un traductor del modo detallado al modo "normal" debería ser una tarea simple. Si le preocupa la legibilidad de sus expresiones regulares, probablemente justifique esta inversión de tiempo con bastante facilidad.
fuente
Cada lenguaje que utiliza expresiones regulares le permite componerlas a partir de bloques más simples para facilitar la lectura, y con cualquier cosa más complicada que (o tan complicada como) su ejemplo, definitivamente debería aprovechar esa opción. El problema particular con Java y muchos otros lenguajes es que no tratan las expresiones regulares como ciudadanos de "primera clase", sino que requieren que se escabullen en el lenguaje a través de literales de cadena. Esto significa muchas comillas y barras invertidas que en realidad no son parte de la sintaxis de expresiones regulares y hacen que las cosas sean difíciles de leer, y también significa que no puede ser mucho más legible que eso sin definir efectivamente su propio mini-idioma e intérprete.
La mejor forma prototípica de integrar expresiones regulares era, por supuesto, Perl, con su opción de espacios en blanco y operadores de comillas de expresiones regulares. Perl 6 amplía el concepto de construir expresiones regulares de partes a gramáticas recursivas reales, que es mucho mejor usar, realmente no hay comparación en absoluto. El lenguaje puede haber perdido el barco de la puntualidad, pero su soporte de expresiones regulares fue The Good Stuff (tm).
fuente
Me gusta usar Expresso: http://www.ultrapico.com/Expresso.htm
Esta aplicación gratuita tiene las siguientes características que encuentro útiles con el tiempo:
Por ejemplo, con la expresión regular que acaba de enviar, se vería así:
Por supuesto, intentarlo vale más que mil palabras para describirlo. Tenga en cuenta también que estoy relacionado de alguna manera con el editor de esta aplicación.
fuente
Para algunas cosas, podría ser útil usar una gramática como BNF. Estos pueden ser mucho más fáciles de leer que las expresiones regulares. Una herramienta como GoldParser Builder puede convertir la gramática en un analizador que haga el trabajo pesado por usted.
Las gramáticas BNF, EBNF, etc. pueden ser mucho más fáciles de leer y crear que una expresión regular complicada. GOLD es una herramienta para tales cosas.
El siguiente enlace wiki de c2 tiene una lista de posibles alternativas que se pueden buscar en Google, con algunas discusiones sobre ellas incluidas. Básicamente es un enlace "ver también" para completar la recomendación de mi motor de gramática:
Alternativas a las expresiones regulares
fuente
Esta es una vieja pregunta y no vi ninguna mención de Expresiones verbales, así que pensé agregar esa información aquí también para futuros buscadores. Las expresiones verbales se diseñaron específicamente para hacer comprensible la expresión regular humana, sin necesidad de aprender el significado del símbolo de expresión regular. Ver el siguiente ejemplo. Creo que esto hace mejor lo que estás pidiendo.
Este ejemplo es para Javascript, puede encontrar esta biblioteca ahora para muchos de los lenguajes de programación.
fuente
La forma más sencilla sería seguir utilizando expresiones regulares, pero construya su expresión componiendo expresiones más simples con nombres descriptivos, por ejemplo, http://www.martinfowler.com/bliki/ComposedRegex.html (y sí, esto es de string concat)
sin embargo, como alternativa, también puede utilizar una biblioteca de combinación de analizadores, por ejemplo, http://jparsec.codehaus.org/, que le proporcionará un analizador decente recursivo completo. Una vez más, el poder real aquí proviene de la composición (esta vez composición funcional).
fuente
Pensé que valdría la pena mencionar de logstash grok expresiones. Grok se basa en la idea de componer expresiones de análisis largas a partir de las más cortas. Permite pruebas convenientes de estos bloques de construcción y viene preempaquetado con más de 100 patrones de uso común . Aparte de estos patrones, permite el uso de todas las sintaxis de expresiones regulares.
El patrón anterior expresado en grok es (lo probé en la aplicación del depurador pero podría haber cometido un error):
Las partes y espacios opcionales hacen que parezca un poco más feo de lo habitual, pero tanto aquí como en otros casos, usar grok puede hacer que la vida sea mucho más agradable.
fuente
En F # tienes el módulo FsVerbalExpressions . Le permite componer expresiones regulares a partir de expresiones verbales, también tiene algunas expresiones regulares precompiladas (como URL).
Uno de los ejemplos de esta sintaxis es el siguiente:
Si no está familiarizado con la sintaxis de F #, groupName es la cadena "GroupNumber".
Luego crean una expresión verbal (VerbEx) que construyen como "COD (? <GroupNumber> [0-9] {3}) END". Que luego prueban en la cadena "COD123END", donde obtienen el grupo de captura con nombre "GroupNumber". Esto da como resultado 123.
Sinceramente, la expresión regular normal es mucho más fácil de comprender.
fuente
Primero, comprenda que el código que simplemente funciona es un código incorrecto. Un buen código también debe informar con precisión cualquier error encontrado.
Por ejemplo, si está escribiendo una función para transferir efectivo de la cuenta de un usuario a la cuenta de otro usuario; no solo devolvería un booleano "trabajado o fallado" porque eso no le da a la persona que llama ninguna idea de lo que salió mal y no le permite informar al usuario correctamente. En cambio, es posible que tenga un conjunto de códigos de error (o un conjunto de excepciones): no se pudo encontrar la cuenta de destino, fondos insuficientes en la cuenta de origen, permiso denegado, no se puede conectar a la base de datos, demasiada carga (vuelva a intentarlo más tarde), etc. .
Ahora piense en su ejemplo de "analizar una cadena de números en formato 1: 2: 3.4". Todo lo que hace la expresión regular es informar un "pasar / fallar" que no permite que se presenten comentarios adecuados al usuario (ya sea que estos comentarios sean un mensaje de error en un registro o una GUI interactiva donde los errores se muestran en rojo como tipos de usuario, o cualquier otra cosa). ¿Qué tipos de errores no describe correctamente? Carácter incorrecto en el primer número, primer número demasiado grande, faltan dos puntos después del primer número, etc.
Para convertir "código incorrecto que simplemente funciona" en "código correcto que proporciona errores descriptivos adecuados", debe dividir la expresión regular en muchas expresiones regulares más pequeñas (por lo general, expresiones regulares que son tan pequeñas que es más fácil hacerlo sin expresiones regulares en primer lugar )
Hacer que el código sea legible / mantenible es solo una consecuencia accidental de hacer que el código sea bueno.
fuente
:
? Imagine un compilador que solo tenía un mensaje de error ("ERROR") que era demasiado estúpido para decirle al usuario cuál es el problema. Ahora imagine miles de sitios web que son tan estúpidos y muestran (por ejemplo) "dirección de correo electrónico incorrecta" y nada más.