¿Hay alguna razón específica para la escasa legibilidad del diseño de sintaxis de expresión regular?

160

Todos los programadores parecen estar de acuerdo en que la legibilidad del código es mucho más importante que las líneas simples sintaxis que funcionan, pero requieren que un desarrollador senior interprete con algún grado de precisión, pero esa parece ser exactamente la forma en que se diseñaron las expresiones regulares. ¿Había alguna razón para esto?

Todos estamos de acuerdo en que selfDocumentingMethodName()es mucho mejor que e(). ¿Por qué eso no se aplica también a las expresiones regulares?

Me parece que en lugar de diseñar una sintaxis de lógica de una línea sin organización estructural:

var parse_url = /^(?:([A-Za-z]+):)?(\/{0,3})(0-9.\-A-Za-z]+)(?::(\d+))?(?:\/([^?#]*))?(?:\?([^#]*))?(?:#(.*))?$/;

¡Y esto ni siquiera es un análisis estricto de una URL!

En cambio, podríamos hacer una estructura de tubería organizada y legible, para un ejemplo básico:

string.regex
   .isRange('A-Z' || 'a-z')
   .followedBy('/r');

¿Qué ventaja ofrece la sintaxis extremadamente breve de una expresión regular que no sea la sintaxis lógica y de operación más corta posible? En última instancia, ¿existe una razón técnica específica para la escasa legibilidad del diseño de sintaxis de expresión regular?

Visir
fuente
Los comentarios no son para discusión extendida; Esta conversación se ha movido al chat .
maple_shaft
1
Intenté abordar exactamente este problema de legibilidad con una biblioteca llamada RegexToolbox. Hasta ahora se ha portado a C #, Java y JavaScript; consulte github.com/markwhitaker/RegexToolbox.CSharp .
Mark Whitaker
Se han hecho muchos intentos para resolver este problema, pero la cultura es difícil de cambiar. Vea mi respuesta sobre expresiones verbales aquí . Las personas buscan la herramienta común más baja disponible.
Parivar Saraff

Respuestas:

178

Hay una gran razón por la cual las expresiones regulares se diseñaron de manera tan concisa como fueron: se diseñaron para usarse como comandos para un editor de código, no como un lenguaje para codificar. Más precisamente, edfue uno de los primeros programas en usar expresiones regulares , y desde allí las expresiones regulares comenzaron su conquista por la dominación mundial. Por ejemplo, el edcomando g/<regular expression>/ppronto inspiró un programa separado llamado grep, que todavía está en uso hoy. Debido a su poder, posteriormente fueron estandarizados y utilizados en una variedad de herramientas como sedyvim

Pero suficiente para la trivia. Entonces, ¿por qué este origen favorecería una gramática breve? Porque no escribes un comando de editor para leerlo ni una vez más. Es suficiente que puedas recordar cómo armarlo, y que puedes hacer las cosas que quieres hacer con él. Sin embargo, cada carácter que tiene que escribir ralentiza su progreso editando su archivo. La sintaxis de la expresión regular fue diseñada para escribir búsquedas relativamente complejas de una manera descartable, y eso es precisamente lo que le da dolor de cabeza a las personas que las usan como código para analizar alguna entrada a un programa.

cmaster
fuente
55
regex no está destinado a analizar. de lo contrario, stackoverflow.com/questions/1732348/… . y dolores de cabeza
njzk2
19
@ njzk2 Esa respuesta es realmente incorrecta. Un documento HTML no es un lenguaje normal, pero en realidad es una etiqueta abierta HTML , que es de lo que se trata la pregunta.
Random832
11
Esta es una buena respuesta que explica por qué la expresión regular original es tan críptica como lo es, pero no explica por qué actualmente no existe un estándar alternativo con mayor legibilidad.
Doc Brown
13
Entonces, para aquellos que piensan que grepes un "agarre" mal pronunciado, en realidad proviene de g/ re(para expresión regular) / p?
Hagen von Eitzen
66
@DannyPflughoeft No, no lo hace. Una etiqueta abierta es justa <aaa bbb="ccc" ddd='eee'>, no hay etiquetas anidadas dentro de ella. No puede anidar etiquetas, lo que anida son elementos (etiqueta abierta, contenido que incluye elementos secundarios, etiqueta de cierre), que la pregunta no era sobre el análisis. Las etiquetas HTML son un lenguaje normal: el equilibrio / anidamiento ocurre en un nivel superior a las etiquetas.
Random832
62

La expresión regular que usted cita es un desastre terrible y no creo que nadie esté de acuerdo en que sea legible. Al mismo tiempo, gran parte de esa fealdad es inherente al problema que se está resolviendo: hay varias capas de anidamiento y la gramática de URL es relativamente complicada (ciertamente demasiado complicada para comunicarse sucintamente en cualquier idioma). Sin embargo, es cierto que hay mejores formas de describir lo que esta expresión regular describe. Entonces, ¿por qué no se usan?

Una gran razón es la inercia y la ubicuidad. No explica cómo se hicieron tan populares en primer lugar, pero ahora que lo son, cualquiera que conozca las expresiones regulares puede usar estas habilidades (con muy pocas diferencias entre dialectos) en cien idiomas diferentes y mil herramientas de software adicionales ( por ejemplo, editores de texto y herramientas de línea de comandos). Por cierto, este último no podría ni podría usar ninguna solución que equivalga a escribir programas , ya que los no programadores los usan mucho.

A pesar de eso, las expresiones regulares a menudo se usan en exceso, es decir, se aplican incluso cuando otra herramienta sería mucho mejor. No creo que la sintaxis de expresiones regulares sea terrible . Pero claramente es mucho mejor con patrones cortos y simples: el ejemplo arquetípico de identificadores en lenguajes tipo C, [a-zA-Z_][a-zA-Z0-9_]*se puede leer con un mínimo absoluto de conocimiento de expresiones regulares y una vez que se cumple esa barra, es obvio y muy sucinto. Requerir menos caracteres no es inherentemente malo, sino todo lo contrario. Ser conciso es una virtud siempre que permanezcas comprensible.

Hay al menos dos razones por las que esta sintaxis sobresale en patrones simples como estos: no requiere escapar para la mayoría de los caracteres, por lo que se lee de forma relativamente natural, y utiliza todos los signos de puntuación disponibles para expresar una variedad de combinadores de análisis simples. Quizás lo más importante, no requiere nada en absoluto para la secuenciación. Escribes lo primero, luego lo que viene después. Compare esto con su followedBy, especialmente cuando el siguiente patrón no es una expresión literal sino más complicada.

Entonces, ¿por qué se quedan cortos en casos más complicados? Puedo ver tres problemas principales:

  1. No hay capacidades de abstracción. Las gramáticas formales, que se originan en el mismo campo de la informática teórica que las expresiones regulares, tienen un conjunto de producciones, por lo que pueden dar nombres a las partes intermedias del patrón:

    # This is not equivalent to the regex in the question
    # It's just a mock-up of what a grammar could look like
    url      ::= protocol? '/'? '/'? '/'? (domain_part '.')+ tld
    protocol ::= letter+ ':'
    ...
    
  2. Como pudimos ver arriba, el espacio en blanco que no tiene un significado especial es útil para permitir un formato que sea más fácil para los ojos. Lo mismo con los comentarios. Las expresiones regulares no pueden hacer eso porque un espacio es solo eso, un literal ' '. Sin embargo, tenga en cuenta que algunas implementaciones permiten un modo "detallado" en el que se ignora el espacio en blanco y es posible realizar comentarios.

  3. No existe un metalenguaje para describir patrones y combinadores comunes. Por ejemplo, uno puede escribir una digitregla una vez y seguir usándola en una gramática libre de contexto, pero no se puede definir una "función", por así decir, que se le da una producción py crea una nueva producción que hace algo extra con ella, por ejemplo, crear una producción para una lista separada por comas de ocurrencias de p.

El enfoque que propone ciertamente resuelve estos problemas. Simplemente no los resuelve muy bien, porque los intercambia con mucha más concisión de lo necesario. Los primeros dos problemas se pueden resolver mientras se mantiene dentro de un lenguaje específico de dominio relativamente simple y conciso. El tercero, bueno ... una solución programática requiere un lenguaje de programación de propósito general, por supuesto, pero en mi experiencia, el tercero es, con mucho, el menor de esos problemas. Pocos patrones tienen suficientes ocurrencias de la misma tarea compleja que el programador anhela la capacidad de definir nuevos combinadores. Y cuando esto es necesario, el lenguaje a menudo es lo suficientemente complicado como para que no pueda y no deba analizarse con expresiones regulares de todos modos.

Existen soluciones para esos casos. Hay aproximadamente diez mil bibliotecas de combinador de analizadores que hacen aproximadamente lo que usted propone, solo con un conjunto diferente de operaciones, a menudo una sintaxis diferente, y casi siempre con más poder de análisis que las expresiones regulares (es decir, tratan con lenguajes libres de contexto o algunos de tamaño considerable subconjunto de esos). Luego están los generadores de analizadores sintácticos, que van con el enfoque de "usar un DSL mejor" descrito anteriormente. Y siempre existe la opción de escribir algunos de los análisis a mano, en el código adecuado. Incluso puede mezclar y combinar, utilizando expresiones regulares para subtareas simples y haciendo las cosas complicadas en el código que invoca las expresiones regulares.

No sé lo suficiente sobre los primeros años de la informática para explicar cómo las expresiones regulares llegaron a ser tan populares. Pero están aquí para quedarse. Solo tiene que usarlos sabiamente y no usarlos cuando sea más sabio.

Tulains Córdova
fuente
99
I don't know enough about the early years of computing to explain how regular expressions came to be so popular.Sin embargo, podemos arriesgarnos a adivinar: un motor de expresión regular básico es muy fácil de implementar, mucho más fácil que un analizador eficiente sin contexto.
biziclop
15
@biziclop No sobreestimaría esta variable. Yacc, que aparentemente tenía suficientes predecesores para ser llamado " otro compilador compilador", se creó a principios de los años 70 y se incluyó en Unix una versión anterior grep(Versión 3 vs Versión 4). Parece que el primer uso importante de
Solo puedo seguir lo que encontré en Wikipedia (por lo que no lo creería al 100%), pero de acuerdo con eso, yaccfue creado en 1975, toda la idea de los analizadores LALR (que se encontraban entre la primera clase de analizadores prácticamente utilizables de sus kind) se originó en 1973. Mientras que la primera implementación del motor regexp que JIT compiló expresiones (!) se publicó en 1968. Pero tienes razón, es difícil decir qué lo hizo girar, de hecho es difícil decir cuándo las expresiones regulares comenzaron a "tomar apagado". Pero sospechaba que una vez que se pusieron en editores de texto que usaron los desarrolladores, también querían usarlos en su propio software.
biziclop
1
@ jpmc26 abre su libro, JavaScript The Good Parts to the Regex Chapter.
Visir el
2
with very few differences between dialectsYo no diría que son "muy pocos". Cualquier clase de caracteres predefinida tiene varias definiciones entre diferentes dialectos. Y también hay peculiaridades de análisis específicas para cada dialecto.
nhahtdh
39

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-stringsiguiente 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-scannery load-time-value:

'(:sequence :start-anchor #.(protocol) #.(slashes) ... )
volcado de memoria
fuente
55
Tal vez solo estoy acostumbrado a la sintaxis tradicional de RegEx, pero no estoy tan seguro de que 22 líneas algo legibles sean más fáciles de entender que las expresiones regulares de una sola línea.
3
@ dan1111 "algo legible" ;-) Está bien, pero si es necesario tener un tiempo muy largo expresiones regulares, que tiene sentido para definir subconjuntos, como digits, identy componerlos. La forma en que lo veo hecho es generalmente con manipulaciones de cadenas (concatenación o interpolación), lo que trae otros problemas como el escape adecuado. Busque las ocurrencias de \\\\`en paquetes de emacs, por ejemplo. Por cierto, esto se agrava debido a que el mismo carácter de escape se utiliza tanto para caracteres especiales como \ny \"y para la sintaxis de expresiones regulares \(. Un ejemplo no lisp de buena sintaxis es printf, donde %dno entra en conflicto con \d.
coredump
1
punto justo sobre los subconjuntos definidos. Eso tiene mucho sentido. Soy escéptico de que la verbosidad sea una mejora. Puede ser más fácil para los principiantes (aunque conceptos como greedy-repetitionno son intuitivos y aún deben ser aprendidos). Sin embargo, sacrifica la usabilidad para los expertos, ya que es mucho más difícil ver y comprender todo el patrón.
@ dan1111 Estoy de acuerdo en que la verbosidad en sí misma no es una mejora. Lo que puede ser una mejora es manipular expresiones regulares utilizando datos estructurados en lugar de cadenas.
coredump
@ dan1111 ¿Quizás debería proponer una edición con Haskell? Parsec lo hace en solo nueve líneas; como una sola línea: do {optional (many1 (letter) >> char ':'); choice (map string ["///","//","/",""]); many1 (oneOf "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-."); optional (char ':' >> many1 digit); optional (char '/' >> many (noneOf "?#")); optional (char '?' >> many (noneOf "#")); optional (char '#' >> many (noneOf "\n")); eof}. Con unas pocas líneas como designar la cadena larga como domainChars = ...y section start p = optional (char start >> many p)parece bastante simple.
CR Drost
25

El mayor problema con la expresión regular no es la sintaxis demasiado breve, es que tratamos de expresar una definición compleja en una sola expresión, en lugar de componerla a partir de bloques de construcción más pequeños. Esto es similar a la programación donde nunca usa variables y funciones y en su lugar incrusta su código en una sola línea.

Compare la expresión regular con BNF . Su sintaxis no es mucho más limpia que la expresión regular, pero se usa de manera diferente. Empieza definiendo símbolos con nombre simples y los compone hasta que llegue a un símbolo que describa el patrón completo que desea hacer coincidir.

Por ejemplo, mire la sintaxis de URI en rfc3986 :

URI           = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
scheme        = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
hier-part     = "//" authority path-abempty
              / path-absolute
              / path-rootless
              / path-empty
...

Podría escribir casi lo mismo usando una variante de la sintaxis de expresiones regulares que admite incrustar subexpresiones con nombre.


Personalmente, creo que una expresión regular breve como la sintaxis está bien para las características de uso común como las clases de caracteres, la concatenación, la elección o la repetición, pero para características más complejas y raras como los nombres detallados de anticipación son preferibles. Muy similar a cómo usamos operadores como +o *en la programación normal y cambiamos a funciones con nombre para operaciones más raras.

CodesInChaos
fuente
12

selfDocumentingMethodName () es mucho mejor que e ()

¿Lo es? Hay una razón por la cual la mayoría de los idiomas tienen {y} como delimitadores de bloque en lugar de BEGIN y END.

A la gente le gusta la terquedad, y una vez que conoce la sintaxis, la terminología corta es mejor. Imagine su ejemplo de expresiones regulares si d (para el dígito) fuera 'dígito', la expresión regular sería aún más horrible de leer. Si lo hiciera más fácil de analizar con caracteres de control, se vería más como XML. Tampoco son tan buenos una vez que conoces la sintaxis.

Sin embargo, para responder adecuadamente a su pregunta, debe darse cuenta de que la expresión regular proviene de los días en que la concisión era obligatoria. Es fácil pensar que un documento XML de 1 MB no es gran cosa hoy, pero estamos hablando de días en que 1 MB era más o menos toda su capacidad de almacenamiento. También se usaban menos idiomas en ese momento, y la expresión regular no está a un millón de millas de distancia de perl o C, por lo que la sintaxis sería familiar para los programadores de la época que estarían felices de aprender la sintaxis. Así que no había razón para hacerlo más detallado.

gbjbaanb
fuente
1
selfDocumentingMethodNameestá generalmente aceptado que ser mejor que eporque la intuición programador no se alinea con la realidad en términos de lo que realmente constituye la legibilidad o código de buena calidad . Las personas que están de acuerdo están equivocadas, pero así es como es.
Leushenko
1
@Leushenko: ¿Estás afirmando que e()es mejor que selfDocumentingMethodName()?
JacquesB
3
@JacquesB tal vez no en todos los contextos (como un nombre global). ¿Pero para cosas de alcance limitado? Casi seguro Definitivamente más a menudo que lo que dice la sabiduría convencional.
Leushenko
1
@Leushenko: Me cuesta imaginar un contexto en el que un nombre de función de una sola letra es mejor que un nombre más descriptivo. Pero supongo que esto es pura opinión.
JacquesB
1
@MilesRout: El ejemplo es en realidad para e()un nombre de método de autodocumentación . ¿Puede explicar en qué contexto es una mejora usar nombres de métodos de una letra en lugar de nombres de métodos descriptivos?
JacquesB
6

Regex es como piezas de lego. A primera vista, verá algunas piezas de plástico de formas diferentes que se pueden unir. Podrías pensar que no habría demasiadas cosas diferentes posibles que puedas moldear, pero luego ves las cosas increíbles que hacen otras personas y te preguntas cómo es un juguete increíble.

Regex es como piezas de lego. Hay pocos argumentos que se pueden usar, pero encadenarlos en diferentes formas formará millones de patrones de expresiones regulares diferentes que se pueden usar para muchas tareas complicadas.

La gente rara vez usaba solo los parámetros de expresiones regulares. Muchos idiomas le ofrecen funciones para verificar la longitud de una cadena o dividir las partes numéricas. Puede usar funciones de cadena para cortar textos y reformarlos. El poder de la expresión regular se nota cuando utiliza formularios complejos para realizar tareas complejas muy específicas.

Puede encontrar decenas de miles de preguntas de expresiones regulares en SO y rara vez se marcan como duplicadas. Esto solo muestra los posibles casos de uso únicos que son muy diferentes entre sí.

Y no es fácil ofrecer métodos predefinidos para manejar estas tareas únicas tan diferentes. Tiene funciones de cadena para ese tipo de tareas, pero si esas funciones no son suficientes para su tarea específica, entonces es hora de usar expresiones regulares.

Ángel caido
fuente
2

Reconozco que este es un problema de práctica más que de potencia. El problema generalmente surge cuando las expresiones regulares se implementan directamente , en lugar de asumir una naturaleza compuesta. Del mismo modo, un buen programador descompondrá las funciones de su programa en métodos concisos.

Por ejemplo, una cadena de expresiones regulares para una URL podría reducirse de aproximadamente:

UriRe = [scheme][hier-part][query][fragment]

a:

UriRe = UriSchemeRe + UriHierRe + "(/?|/" + UriQueryRe + UriFragRe + ")"
UriSchemeRe = [scheme]
UriHierRe = [hier-part]
UriQueryRe = [query]
UriFragRe = [fragment]

Las expresiones regulares son cosas ingeniosas, pero son propensas a ser abusadas por aquellos que se vuelven absortos en su aparente complejidad. Las expresiones resultantes son retóricas, ausentes de un valor a largo plazo.

toplel32
fuente
2
Desafortunadamente, la mayoría de los lenguajes de programación no incluyen funcionalidad que ayude a componer expresiones regulares y la forma en que funciona la captura de grupo tampoco es muy amigable para la composición.
CodesInChaos
1
Otros idiomas necesitan ponerse al día con Perl 5 en su soporte de "expresión regular compatible con Perl". Las subexpresiones no son lo mismo que simplemente concatenar cadenas de especificación de expresiones regulares. Las capturas deben ser nombradas, sin depender de la numeración implícita.
JDługosz
0

Como dice @cmaster, las expresiones regulares se diseñaron originalmente para usarse solo sobre la marcha, y es simplemente extraño (y un poco deprimente) que la sintaxis de ruido de línea siga siendo la más popular. Las únicas explicaciones que se me ocurren son la inercia, el masoquismo o el machismo (no es frecuente que la "inercia" sea la razón más atractiva para hacer algo ...)

Perl hace un intento bastante débil de hacerlos más legibles al permitir espacios en blanco y comentarios, pero no hace nada remotamente imaginativo.

Hay otras sintaxis. Una buena es la sintaxis scsh para regexps , que en mi experiencia produce expresiones regulares que son razonablemente fáciles de escribir, pero aún legibles después del hecho.

[ scsh es espléndido por otros motivos, uno de los cuales es su famoso texto de agradecimientos ]

Gris normando
fuente
2
Perl6 hace! Mira las gramáticas.
JDługosz
@ JDługosz Hasta donde puedo ver, parece más un mecanismo para generadores de analizadores, en lugar de una sintaxis alternativa para expresiones regulares. Pero la distinción quizás no sea profunda.
Norman Gray
Puede ser un reemplazo, pero no se limita al mismo poder. Puede traducir un regedp en una gramática en línea con correspondencia 1 a 1 de los modificadores pero en una sintaxis más legible. Los ejemplos que lo promueven como tal están en el Apocalipsis Perl original.
JDługosz
0

Creo que las expresiones regulares fueron diseñadas para ser tan 'generales' y simples como sea posible, por lo que pueden usarse (aproximadamente) de la misma manera en cualquier lugar.

regex.isRange(..).followedBy(..)Su ejemplo está acoplado tanto a la sintaxis de un lenguaje de programación específico como a un estilo orientado a objetos (encadenamiento de métodos).

¿Cómo se vería exactamente esta 'expresión regular' en C, por ejemplo? El código tendría que ser cambiado.

El enfoque más "general" sería definir un lenguaje conciso simple que luego pueda integrarse fácilmente en cualquier otro idioma sin cambios. Y eso es (casi) lo que son las expresiones regulares.

Aviv Cohn
fuente
0

Los motores de expresión regular compatibles con Perl se usan ampliamente, proporcionando una sintaxis de expresión regular concisa que muchos editores e idiomas entienden. Como @JDługosz señaló en los comentarios, Perl 6 (no solo una nueva versión de Perl 5, sino un lenguaje completamente diferente) ha intentado hacer que las expresiones regulares sean más legibles al construirlas a partir de elementos definidos individualmente. Por ejemplo, aquí hay una gramática de ejemplo para analizar URL de Wikilibros :

grammar URL {
  rule TOP {
    <protocol>'://'<address>
  }
  token protocol {
    'http'|'https'|'ftp'|'file'
  }
  rule address {
    <subdomain>'.'<domain>'.'<tld>
  }
  ...
}

Dividir la expresión regular de esta manera permite que cada bit se defina individualmente (por ejemplo, restringir domaina ser alfanumérico) o extenderse a través de subclases (por ejemplo, FileURL is URLque las restricciones protocolsean solo "file").

Entonces: no, no hay una razón técnica para la brevedad de las expresiones regulares, ¡pero las formas más nuevas, más limpias y más legibles de representarlas ya están aquí! Esperemos ver algunas ideas nuevas en este campo.

Gaurav
fuente