Perspectiva historica
El artículo de Wikipedia es bastante detallado sobre los orígenes de las expresiones regulares (Kleene, 1956). La sintaxis original relativamente simple, con solamente *
, +
, ?
, |
y agrupación (...)
. Fue breve ( y legible, los dos no son necesariamente opuestos), porque los lenguajes formales tienden a expresarse con notables anotaciones matemáticas.
Más tarde, la sintaxis y las capacidades evolucionaron con los editores y crecieron con Perl , que intentaba ser breve por diseño ( "las construcciones comunes deberían ser cortas" ). Esto complementó mucho la sintaxis, pero tenga en cuenta que las personas ahora están acostumbradas a las expresiones regulares y son buenas para escribirlas (si no leerlas). El hecho de que a veces son de solo escritura sugiere que cuando son demasiado largos, generalmente no son la herramienta adecuada.
Las expresiones regulares tienden a ser ilegibles cuando se abusa de ellas.
Más allá de las expresiones regulares basadas en cadenas
Hablando de sintaxis alternativas, echemos un vistazo a una que ya existe ( cl-ppcre , en Common Lisp ). Su expresión regular larga se puede analizar de la ppcre:parse-string
siguiente manera:
(let ((*print-case* :downcase)
(*print-right-margin* 50))
(pprint
(ppcre:parse-string "^(?:([A-Za-z]+):)?(\\/{0,3})(0-9.\\-A-Za-z]+)(?::(\\d+))?(?:\\/([^?#]*))?(?:\\?([^#]*))?(?:#(.*))?$")))
... y da como resultado la siguiente forma:
(:sequence :start-anchor
(:greedy-repetition 0 1
(:group
(:sequence
(:register
(:greedy-repetition 1 nil
(:char-class (:range #\A #\Z)
(:range #\a #\z))))
#\:)))
(:register (:greedy-repetition 0 3 #\/))
(:register
(:sequence "0-9" :everything "-A-Za-z"
(:greedy-repetition 1 nil #\])))
(:greedy-repetition 0 1
(:group
(:sequence #\:
(:register
(:greedy-repetition 1 nil :digit-class)))))
(:greedy-repetition 0 1
(:group
(:sequence #\/
(:register
(:greedy-repetition 0 nil
(:inverted-char-class #\? #\#))))))
(:greedy-repetition 0 1
(:group
(:sequence #\?
(:register
(:greedy-repetition 0 nil
(:inverted-char-class #\#))))))
(:greedy-repetition 0 1
(:group
(:sequence #\#
(:register
(:greedy-repetition 0 nil :everything)))))
:end-anchor)
Esta sintaxis es más detallada, y si observa los comentarios a continuación, no necesariamente es más legible. Así que no asuma que debido a que tiene una sintaxis menos compacta, las cosas se aclararán automáticamente .
Sin embargo, si comienza a tener problemas con sus expresiones regulares, convertirlas a este formato podría ayudarlo a descifrar y depurar su código. Esta es una ventaja sobre los formatos basados en cadenas, donde un error de un solo carácter puede ser difícil de detectar.
La principal ventaja de esta sintaxis es manipular expresiones regulares utilizando un formato estructurado en lugar de una codificación basada en cadenas. Eso le permite componer y construir expresiones como cualquier otra estructura de datos en su programa. Cuando uso la sintaxis anterior, esto generalmente se debe a que quiero construir expresiones a partir de partes más pequeñas (consulte también mi respuesta de CodeGolf ). Para su ejemplo, podemos escribir 1 :
`(:sequence
:start-anchor
,(protocol)
,(slashes)
,(domain)
,(top-level-domain) ... )
Las expresiones regulares basadas en cadenas también se pueden componer, utilizando la concatenación de cadenas y / o la interpolación envuelta en funciones auxiliares. Sin embargo, existen limitaciones con las manipulaciones de cadenas que tienden a desordenar el código (piense en problemas de anidación, no muy diferente de los backticks vs. $(...)
en bash; también, los caracteres de escape pueden causar dolores de cabeza).
Tenga en cuenta también que el formulario anterior permite (:regex "string")
formularios para que pueda mezclar anotaciones concisas con árboles. Todo eso lleva a mi humilde opinión a una buena legibilidad y componibilidad; aborda los tres problemas expresados por delnan , indirectamente (es decir, no en el lenguaje de las expresiones regulares en sí).
Para concluir
Para la mayoría de los propósitos, la notación concisa es de hecho legible. Existen dificultades cuando se trata de notaciones extendidas que implican retroceso, etc., pero su uso rara vez se justifica. El uso injustificado de expresiones regulares puede conducir a expresiones ilegibles.
Las expresiones regulares no necesitan ser codificadas como cadenas. Si tiene una biblioteca o una herramienta que puede ayudarlo a construir y componer expresiones regulares, evitará muchos errores potenciales relacionados con las manipulaciones de cadenas.
Alternativamente, las gramáticas formales son más legibles y son mejores para nombrar y abstraer subexpresiones. Las terminales generalmente se expresan como simples expresiones regulares.
1. Es posible que prefiera construir sus expresiones en el momento de la lectura, porque las expresiones regulares tienden a ser constantes en una aplicación. Ver create-scanner
y load-time-value
:
'(:sequence :start-anchor #.(protocol) #.(slashes) ... )