Diseño de una Alternativa (Fluent?) Interfaz para Expresiones Regulares


Acabo de ver una enorme expresión regular para Java que me hizo pensar un poco sobre la mantenibilidad de las expresiones regulares en general. Creo que la mayoría de la gente - excepto algunos malvados perl mongers - estaría de acuerdo en que las expresiones regulares son difícilmente mantenibles.

Estaba pensando en cómo se podría arreglar esta situación. Hasta ahora, la idea más prometedora que tengo es usar una interfaz fluida . Para dar un ejemplo, en lugar de:

Pattern pattern = Pattern.compile("a*|b{2,5}");

Uno podría escribir algo como esto

import static util.PatternBuilder.*

Pattern pattern = string("a").anyTimes().or().string("b").times(2,5).compile();

Pattern alternative = 
  or(
    string("a").anyTimes(),
    string("b").times(2,5)
  )
  .compile();

En este breve ejemplo, la forma común de crear expresiones regulares todavía es bastante legible para cualquier desarrollador talentoso mediocre. Sin embargo, piense en esas expresiones espeluznantes que llenan dos o más líneas con 80 caracteres cada una. Claro, la interfaz fluida (verbosa) requeriría varias líneas en lugar de solo dos, pero estoy seguro de que sería mucho más legible (por lo tanto, mantenible).

Ahora mis preguntas:

  1. ¿Conoces algún enfoque similar ¿a expresiones regulares?

  2. ¿Estás de acuerdo en que este enfoque podría ser mejor que usar cadenas simples?

  3. ¿Cómo diseñarías la API?

  4. ¿Usarías una utilidad tan ordenada en tus proyectos?

  5. ¿Crees que sería divertido implementarlo? ;)

EDITAR: Imagine que podría haber métodos que están en un nivel más alto que construcciones simples que todos no de regex, e. g.

// matches [email protected] - think of it as reusable expressions
Pattern p = string{"a").anyTimes().string("b@").domain().compile();

EDITAR-breve resumen de comentarios:

Es interesante lea que la mayoría de la gente piensa que las expresiones regulares están aquí para quedarse, aunque se necesitan herramientas para leerlas y chicos inteligentes para pensar en formas de hacerlas mantenibles. Si bien no estoy seguro de que una interfaz fluida sea la mejor manera de hacerlo, estoy seguro de que algunos ingenieros inteligentes, ¿nosotros? ;)- debe pasar algún tiempo para hacer expresiones regulares una cosa del pasado - es suficiente que han estado con nosotros durante 50 años saben, ¿no crees?

OPEN BOUNTY

La recompensa será otorgado a la mejor idea (no se requiere código) para un nuevo enfoque de las expresiones regulares.

EDITAR-UN BUEN EJEMPLO:

Este es el tipo de patrón del que estoy hablando - felicitaciones adicionales al primero que sea capaz de traducirlo - RegexBuddies permitido (es de un proyecto Apache por cierto) felicitaciones adicionales otorgadas a chii y mez: es un patrón de validación de direcciones de correo electrónico compatible con RFC - aunque su RFC822 (ver ex-parrot.com ), no 5322 - sin embargo, no estoy seguro de si hay una diferencia, si es así, otorgaré el siguiente reconocimiento adicional por un parche que se ajuste a 5322;)

private static final String pattern = "(?:(?:\\r\\n)?[ \\t])*(?:(?:(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t]"
    + ")+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:"
    + "\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:("
    + "?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ "
    + "\\t]))*\"(?:(?:\\r\\n)?[ \\t])*))*@(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\0"
    + "31]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\"
    + "](?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+"
    + "(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:"
    + "(?:\\r\\n)?[ \\t])*))*|(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z"
    + "|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)"
    + "?[ \\t])*)*\\<(?:(?:\\r\\n)?[ \\t])*(?:@(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\"
    + "r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?["
    + " \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)"
    + "?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t]"
    + ")*))*(?:,@(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?["
    + " \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*"
    + ")(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t]"
    + ")+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*)"
    + "*:(?:(?:\\r\\n)?[ \\t])*)?(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+"
    + "|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r"
    + "\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:"
    + "\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t"
    + "]))*\"(?:(?:\\r\\n)?[ \\t])*))*@(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031"
    + "]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\]("
    + "?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?"
    + ":(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?"
    + ":\\r\\n)?[ \\t])*))*\\>(?:(?:\\r\\n)?[ \\t])*)|(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?"
    + ":(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?"
    + "[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*)*:(?:(?:\\r\\n)?[ \\t])*(?:(?:(?:[^()<>@,;:\\\".\\[\\] "
    + "\\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|"
    + "\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>"
    + "@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\""
    + "(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*))*@(?:(?:\\r\\n)?[ \\t]"
    + ")*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\\"
    + "\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?"
    + ":[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\["
    + "\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*|(?:[^()<>@,;:\\\".\\[\\] \\000-"
    + "\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|("
    + "?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*)*\\<(?:(?:\\r\\n)?[ \\t])*(?:@(?:[^()<>@,;"
    + ":\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[(["
    + "^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\""
    + ".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\"
    + "]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*(?:,@(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\"
    + "[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\"
    + "r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] "
    + "\\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]"
    + "|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*)*:(?:(?:\\r\\n)?[ \\t])*)?(?:[^()<>@,;:\\\".\\[\\] \\0"
    + "00-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\"
    + ".|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,"
    + ";:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\"(?"
    + ":[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*))*@(?:(?:\\r\\n)?[ \\t])*"
    + "(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\"."
    + "\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:["
    + "^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]"
    + "]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*\\>(?:(?:\\r\\n)?[ \\t])*)(?:,\\s*("
    + "?:(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\\"
    + "\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:("
    + "?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=["
    + "\\[\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t"
    + "])*))*@(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t"
    + "])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*)(?"
    + ":\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|"
    + "\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*|(?:"
    + "[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\"
    + "]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*)*\\<(?:(?:\\r\\n)"
    + "?[ \\t])*(?:@(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\""
    + "()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)"
    + "?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>"
    + "@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*(?:,@(?:(?:\\r\\n)?["
    + " \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,"
    + ";:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t]"
    + ")*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\\"
    + "\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*)*:(?:(?:\\r\\n)?[ \\t])*)?"
    + "(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\"."
    + "\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:"
    + "\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\["
    + "\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])"
    + "*))*@(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])"
    + "+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*)(?:\\"
    + ".(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z"
    + "|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*\\>(?:("
    + "?:\\r\\n)?[ \\t])*))*)?;\\s*)";
Author: Community, 2009-10-16

18 answers

¿Cómo diseñarías la API?

Me gustaría tomar prestada una página de la API de criterios de Hibernación. En lugar de usar:

string("a").anyTimes().or().string("b").times(2,5).compile()

Usa un patrón como:

Pattern.or(Pattern.anyTimes("a"), Pattern.times("b", 2, 5)).compile()

Esta notación es un poco más concisa, y siento que es más fácil entender la jerarquía/estructura del patrón. Cada método puede aceptar una cadena o un fragmento de patrón como primer argumento.

¿Conoce algún enfoque similar a las expresiones regulares?

No de improviso, no.

¿Estás de acuerdo en que este enfoque podría ser mejor que usar cadenas simples?

Sí, absolutamente... si está utilizando expresiones regulares para algo remotamente complicado. Para casos muy cortos y simples, una cadena es más conveniente.

¿Usarías una utilidad tan ordenada en tus proyectos?

Posiblemente, ya que se demostró/estable... rodarlo en un proyecto de utilidad más grande como Apache Commons podría ser una ventaja.

¿crees que esto sería ¿diversión implementando? ;)

+1

 7
Author: RMorrisey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-10-23 23:41:24

Martin Fowler sugiere otra estrategia . Es decir, tomar partes significativas de la expresión regular y reemplazarlas por variables. Él usa el siguiente ejemplo:

 "^score\s+(\d+)\s+for\s+(\d+)\s+nights?\s+at\s+(.*)" 

Se convierte en

   String scoreKeyword = "^score\s+";
   String numberOfPoints = "(\d+)";
   String forKeyword = "\s+for\s+";
   String numberOfNights = "(\d+)";
   String nightsAtKeyword = "\s+nights?\s+at\s+";
   String hotelName = "(.*)";

   String pattern = scoreKeyword + numberOfPoints +
      forKeyword + numberOfNights + nightsAtKeyword + hotelName;

Que es mucho más legible y mantenible.

El objetivo del ejemplo anterior era analizar numberOfPoints, numberOfNights y hotelName de una Lista de Cadenas como:

score 400 for 2 nights at Minas Tirith Airport
 19
Author: Dominik,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-10-16 20:52:06

Podría ser un poco más fácil para alguien sin ninguna experiencia de expresiones regulares, pero después de que alguien aprenda su sistema, todavía no será capaz de leer una expresión regular normal en otro lugar.

También, creo que su versión es más difícil de leer para un experto regex.

Yo recomendaría anotar la expresión regular así:

Pattern pattern = Pattern.compile(
  "a*     # Find 0 or more a        \n" +
  "|      # ... or ...              \n" +
  "b{2,5} # Find between 2 and 5 b  \n",
Pattern.COMMENTS);

Esto es fácil de leer para cualquier nivel de experiencia, y para los inexpertos, enseña expresiones regulares al mismo tiempo. Además, los comentarios se pueden adaptar a la situación para explique las reglas de negocio detrás de la expresión regular en lugar de solo la estructura.

Además, una herramienta como RegexBuddy puede tomar tu expresión regular y traducirla a:

Match either the regular expression below (attempting the next alternative only if this one fails) «a*»
   Match the character "a" literally «a*»
      Between zero and unlimited times, as many times as possible, giving back as needed (greedy) «*»
Or match regular expression number 2 below (the entire match attempt fails if this one fails to match) «b{2,5}»
   Match the character "b" literally «b{2,5}»
      Between 2 and 5 times, as many times as possible, giving back as needed (greedy) «{2,5}»
 18
Author: Jeremy Stein,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-10-16 20:47:53

Este es un concepto intrigante, pero como se presenta hay algunos defectos.

Pero las primeras respuestas a las preguntas clave hechas:

Ahora mis preguntas:

1. ¿Conoce algún enfoque similar a las expresiones regulares?

Ninguno que no haya sido mencionado ya. Y los descubrí leyendo la pregunta y las respuestas.

2. ¿Está de acuerdo en que este enfoque podría ser mejor que usar simple ¿cuerdas?

Si funciona como se anuncia, definitivamente haría las cosas mucho más fáciles de depurar.

3. ¿Cómo diseñarías la API?

Ver mis notas en la siguiente sección. Tomo sus ejemplos y la biblioteca. NET vinculada como punto de partida.

4. ¿Usarías una utilidad tan ordenada en tus proyectos?

Indecisos. No tengo ningún problema trabajando con la versión actual de expresiones regulares crípticas. Y necesitaría una herramienta para convertir expresiones regulares existentes a la versión de idioma fluido.

5. ¿Crees que sería divertido implementarlo? ;)

Me gustaría trabajar en el nivel más alto cómo, que escribir el código real. Lo que explica el muro de texto que es esta respuesta.


Aquí hay un par de problemas que noté, y la forma en que lo manejaría.

Estructura poco clara.

Su ejemplo parece crear una expresión regular al concatenar cadenas. Esto no es muy robusto. Creo que estos métodos deberían agregarse a los objetos String y Patern/Regex, porque hará que la implementación y el código sean más limpios. Además, es similar a la forma en que las Expresiones Regulares se definen clásicamente.

Solo porque no puedo ver que funcione de otra manera, el resto de mis anotaciones al esquema propuesto asumirán que todos los métodos actúan y devuelven objetos de patrón.

Editar: Parece que he utilizado las siguientes convenciones durante. Así que las he aclarado y las he traído aquí.

  • Métodos de instancia: aumento de patrones. por ejemplo: capturar, repetir, mirar alrededor de afirmaciones.

  • Operadores: orden de operaciones. alternation, concatenation

  • Constantes: clases de caracteres, límites (en lugar de \w,\, \ b, etc.)

¿Cómo se manejará la captura/clustering?

Capturar es una gran parte de las expresiones regulares.

I vea cada objeto de patrón almacenado internamente como un clúster. (?: patrón) en términos de Perl. Permitiendo que las fichas de patrones se mezclen y mezclen fácilmente sin interferir con otras piezas.

Espero que la captura se haga como un método de instancia en un Patrón. Tomando una variable para almacenar la cadena[s] coincidente.

pattern.capture(variable) almacenaría patrón en variable. En el caso de que la captura sea parte de una expresión que se empareje varias veces, la variable debe contener una matriz de cadenas de todos los partidos para el patrón.

Las lenguas fluidas pueden ser muy ambiguas.

Las lenguas fluidas no se adaptan bien a la naturaleza recursiva de las expresiones regulares. Por lo tanto, hay que tener en cuenta el orden de las operaciones. Solo encadenar métodos juntos no permite expresiones regulares muy complejas. Exactamente la situación en la que tal herramienta sería útil.

Lo hace

Pattern pattern = string("a").anyTimes().or().string("b").times(2,5).compile();

Produce /a*|b{2,5}/ o /(a*|b){2,5}/?

¿Cómo manejaría tal esquema anidado alternancia? Eg: /a*|b(c|d)|e/

Veo tres formas de manejar la alternancia en expresiones regulares

  1. Como operador: pattern1 or pattern2 => pattern # /pattern1|pattern2/
  2. Como método de clase: Pattern.or( pattern1, pattern2[, pattern3]*) => pattern # /pattern1|patern2|patern3|...|/
  3. Como método de instancia: pattern1.or(pattern2) => pattern # /pattern1|patern2/

Yo manejaría la concatenación de la misma manera.

  1. Como operador: pattern1 + pattern2 => pattern # /pattern1pattern2/
  2. Como método de clase: Pattern.concatenate( pattern1, pattern2[, pattern3]*) => pattern # /pattern1patern2patern3.../
  3. Como método de instancia: pattern1.then(pattern2) => pattern # /pattern1patern2/

Cómo extender para patrones de uso común

El esquema propuesto utilizado .domain() que parece ser una expresión regular común. Tratar los patrones definidos por el usuario como métodos no facilita la adición de nuevos patrones. En un lenguaje como Java, los usuarios de la biblioteca tendrían que reemplazar la clase para agregar métodos para patrones comúnmente utilizados.

Esto es abordado por mi sugerencia de tratar cada pieza como un objeto. Se puede crear un objeto de patrón para cada expresión regular comúnmente utilizada, como la coincidencia de un dominio, por ejemplo. Teniendo en cuenta mis pensamientos anteriores sobre capturarlo no sería demasiado difícil asegurarse de que la captura funciona para varias copias del mismo patrón común que contiene una sección capturada.

También debe haber constantes para patrones que coincidan con varias clases de caracteres.

Anchura cero mira alrededor aserciones

Expandiendo mis pensamientos de que todas las piezas deben estar implícitamente agrupadas. Mirar alrededor las aserciones no deberían ser demasiado difíciles de hacer con un método de instancia.

pattern.zeroWidthLookBehind() produciría (?<patten).


Cosas que todavía necesitan ser consideradas.

  • Backreferences: Esperemos que no sea demasiado difícil con la captura nombrada discutida anteriormente
  • Cómo implementarlo realmente. No he pensado demasiado en los internos. Es donde la verdadera magia va a suceder.
  • Traducción: Realmente debería haber una herramienta traducir hacia y desde expresiones regulares clásicas (digamos dialecto Perl) y el nuevo esquema. Traducción del nuevo esquema podría ser una parte de la paquete

Poniendo todo junto, mi versión propuesta de un patrón que coincide con una dirección de correo electrónico:

Pattern domain_label = LETTER_CHARACTER + (LETTER_CHARACTER or "-" or DIGIT_CHARACTER).anyTimes()
Pattern domain = domain_label + ("." + domain_label).anyTimes()
Pattern pattern = (LETTER_CHARACTER + ALPHANUMERIC_CHARACTER + "@" + domain).compile

En retrospectiva, mi esquema se basa en gran medida en el enfoque de Martin Fowler en uso. Aunque no tenía la intención de que las cosas fueran de esta manera, definitivamente hace que el uso de un sistema de este tipo sea más mantenible. También aborda un problema o dos con el enfoque de Fowler (orden de captura).

 10
Author: EmFi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-10-20 14:23:40

Mi propio intento humilde se puede encontrar en GitHub. Aunque no creo que valga la pena usarlo para expresiones simples, proporciona un par de ventajas aparte de la mejora de la legibilidad:

  • Se encarga de la coincidencia de corchetes
  • Maneja el escape de todos los caracteres' especiales ' que pueden conducir rápidamente al infierno de la barra invertida

Algunos ejemplos simples:

 // Matches a single digit
    RegExBuilder.build(anyDigit()); // "[0-9]"

 // Matches exactly 2 digits
    RegExBuilder.build(exactly(2).of(anyDigit())); // "[0-9]{2}"

 // Matches between 2 and 4 letters
    RegExBuilder.build(between(2,4).of(anyLetter())); // "[a-zA-Z]{2,4}"

Y uno más complicado (que más o menos valida el correo electrónico direcciones):

final Token ALPHA_NUM = anyOneOf(range('A','Z'), range('a','z'), range('0','9'));
final Token ALPHA_NUM_HYPEN_UNDERSCORE = anyOneOf(characters('_','-'), range('A','Z'), range('a','z'), range('0','9'));

String regexText = RegExBuilder.build(
 // Before the '@' symbol we can have letters, numbers, underscores and hyphens anywhere
    oneOrMore().of(
        ALPHA_NUM_HYPEN_UNDERSCORE
    ),
    zeroOrMore().of(
        text("."), // Periods are also allowed in the name, but not as the initial character
        oneOrMore().of(
            ALPHA_NUM_HYPEN_UNDERSCORE
        )
    ),
    text("@"),
 // Everything else is the domain name - only letters, numbers and periods here
    oneOrMore().of( 
        ALPHA_NUM
    ),
    zeroOrMore().of(
        text("."), // Periods must not be the first character in the domain
        oneOrMore().of(
            ALPHA_NUM
        )
    ),
    text("."), // At least one period is required
    atLeast(2).of( // Period must be followed by at least 2 letters (this is the TLD)
        anyLetter()
    )
);
 7
Author: codebox,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-12-29 18:18:48

Hay una biblioteca de expresiones regulares fluidas para .NET.

 6
Author: elder_george,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-10-16 16:23:30

Respuesta corta: Lo he visto acercarse desde un ángulo de linting y compilación, que creo que es algo a considerar para esto.

Respuesta Larga: La empresa para la que trabajo fabrica motores de expresión regular basados en hardware para aplicaciones de filtrado de contenido empresarial. Piense en ejecutar aplicaciones antivirus o de firewall a velocidades de 20 GB/seg directamente en los enrutadores de red en lugar de ocupar valiosos ciclos de servidor o procesador. La mayoría de las aplicaciones antivirus, antispam o firewall son un montón de expresiones regulares expresiones en el centro.

De todos modos, la forma en que se escriben las expresiones regulares tiene un gran impacto en el rendimiento del escaneo. Puede escribir expresiones regulares de varias maneras diferentes para hacer lo mismo, y algunas tendrán un rendimiento drásticamente más rápido. Hemos escrito compiladores y linters para nuestros clientes para ayudarles a mantener y afinar sus expresiones.

Volviendo a la pregunta del OP, en lugar de definir una sintaxis completamente nueva, escribiría un linter (lo siento, el nuestro es propietario) pegue expresiones regulares en que se desglosan las expresiones regulares heredadas y la salida "inglés fluido" para que alguien entienda mejor. También añadiría comprobaciones de rendimiento relativas y sugerencias para modificaciones comunes.

 4
Author: SDGator,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-10-20 19:01:28

La respuesta corta, para mí, es que, una vez que se llega a las expresiones regulares (u otra coincidencia de patrones que hace lo mismo) que son lo suficientemente largas como para causar un problema... probablemente deberías considerar si son la herramienta adecuada para el trabajo en primer lugar.

Honestamente, cualquier interfaz fluida parece que sería más difícil de leer que una expresión regular estándar. Para expresiones realmente cortas, la versión fluida es detallada, pero no demasiado larga; es legible. Pero también lo es el regular expresión para algo tan largo.

Para una expresión regular de tamaño medio, una interfaz fluida se vuelve difícil de manejar; lo suficientemente larga como para que sea difícil, si no imposible, de leer.

Para una expresión regular larga (es decir, la dirección de correo electrónico), donde la expresión regular es realmente difícil (si no imposible) de leer, la versión fluida se volvió imposible de leer hace 10 páginas.

 4
Author: RHSeeger,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-10-23 03:34:59

¿Conoce algún enfoque similar a las expresiones regulares?

No, excepto la respuesta anterior

¿Estás de acuerdo en que este enfoque podría ser mejor que usar cadenas simples?

Más o menos - Creo que en lugar de caracteres individuales para representar construcciones, podríamos usar un marcado más descriptivo, pero dudo que haga más clara la lógica compleja.

¿Cómo diseñarías la API?

Traduce cada constructo en un método nombre, y permitir llamadas a funciones anidadas para que sea muy fácil tomar una cadena y sustituir los nombres de los métodos en ella.

Creo que la mayor parte del valor estará en la definición de una biblioteca robusta de funciones de utilidad, como la coincidencia de "correos electrónicos", "números de teléfono", "líneas que no contienen X", etc. eso se puede personalizar.

¿Usarías una utilidad tan ordenada en tus proyectos?

Tal vez, pero probablemente solo para los más largos, donde sería más fácil depurar la función llamadas que la depuración de la edición de cadenas, o donde hay una buena función de utilidad lista para usar.

¿Crees que sería divertido implementarlo? ;)

¡por supuesto!

 1
Author: Jeff Meatball Yang,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-10-16 16:43:25

En respuesta a la última parte de la pregunta (para Felicitaciones)

private static final String pattern = "(?:(?:\\r\\n)?[ \\t])*(?:(?:(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t]"
    + ")+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:"
    + "\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:("
    + "?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ "
    + "\\t]))*\"(?:(?:\\r\\n)?[ \\t])*))*@(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\0"
    + "31]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\"
    + "](?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+"
    + "(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:"
    + "(?:\\r\\n)?[ \\t])*))*|(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z"
    + "|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)"
    + "?[ \\t])*)*\\<(?:(?:\\r\\n)?[ \\t])*(?:@(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\"
    + "r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?["
    + " \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)"
    + "?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t]"
    + ")*))*(?:,@(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?["
    + " \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*"
    + ")(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t]"
    + ")+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*)"
    + "*:(?:(?:\\r\\n)?[ \\t])*)?(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+"
    + "|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r"
    + "\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:"
    + "\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t"
    + "]))*\"(?:(?:\\r\\n)?[ \\t])*))*@(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031"
    + "]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\]("
    + "?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?"
    + ":(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?"
    + ":\\r\\n)?[ \\t])*))*\\>(?:(?:\\r\\n)?[ \\t])*)|(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?"
    + ":(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?"
    + "[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*)*:(?:(?:\\r\\n)?[ \\t])*(?:(?:(?:[^()<>@,;:\\\".\\[\\] "
    + "\\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|"
    + "\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>"
    + "@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\""
    + "(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*))*@(?:(?:\\r\\n)?[ \\t]"
    + ")*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\\"
    + "\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?"
    + ":[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\["
    + "\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*|(?:[^()<>@,;:\\\".\\[\\] \\000-"
    + "\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|("
    + "?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*)*\\<(?:(?:\\r\\n)?[ \\t])*(?:@(?:[^()<>@,;"
    + ":\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[(["
    + "^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\""
    + ".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\"
    + "]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*(?:,@(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\"
    + "[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\"
    + "r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] "
    + "\\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]"
    + "|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*)*:(?:(?:\\r\\n)?[ \\t])*)?(?:[^()<>@,;:\\\".\\[\\] \\0"
    + "00-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\"
    + ".|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,"
    + ";:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\"(?"
    + ":[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*))*@(?:(?:\\r\\n)?[ \\t])*"
    + "(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\"."
    + "\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:["
    + "^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]"
    + "]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*\\>(?:(?:\\r\\n)?[ \\t])*)(?:,\\s*("
    + "?:(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\\"
    + "\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:("
    + "?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=["
    + "\\[\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t"
    + "])*))*@(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t"
    + "])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*)(?"
    + ":\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|"
    + "\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*|(?:"
    + "[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\"
    + "]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*)*\\<(?:(?:\\r\\n)"
    + "?[ \\t])*(?:@(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\""
    + "()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)"
    + "?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>"
    + "@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*(?:,@(?:(?:\\r\\n)?["
    + " \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,"
    + ";:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t]"
    + ")*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\\"
    + "\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*)*:(?:(?:\\r\\n)?[ \\t])*)?"
    + "(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\"."
    + "\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:"
    + "\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\["
    + "\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])"
    + "*))*@(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])"
    + "+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*)(?:\\"
    + ".(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z"
    + "|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*\\>(?:("
    + "?:\\r\\n)?[ \\t])*))*)?;\\s*)";

Coincide con las direcciones de correo electrónico compatibles con RFC: D

 1
Author: Mez,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-10-20 12:37:54

Una expresión regular es una descripción de una máquina de estados finitos. La representación textual clásica no es necesariamente mala. Es compacto, es relativamente inequívoco y está bastante bien adoptado.

Puede ser que una mejor representación sea un diagrama de transición de estados, pero eso probablemente sería difícil de usar en el código fuente.

Una posibilidad sería construirlo a partir de una variedad de objetos contenedor y combinador.

Algo en la línea de lo siguiente (convertir esto de pseudo-código a lenguaje de elección se deja como un ejercicio para los ansiosos):

domainlabel = oneormore(characterclass("a-zA-Z0-9-"))
separator = literal(".")
domain = sequence(oneormore(sequence(domainlabel, separator)), domainlabel)
localpart = oneormore(characterclassnot("@"))
emailaddress = sequence(localpart, literal("@"), domain)

Tenga en cuenta que lo anterior clasificará incorrectamente muchas direcciones de correo electrónico como válidas que NO se ajustan a la gramática que deben seguir, ya que esa gramática requiere más que un simple FSM para el análisis completo. Aunque no creo que clasifique erróneamente una dirección válida como inválida.

Debería corresponder a [^@] +@([a -A-Z0-9 -]+.)+.([a -A-Z0-9 -]+)

 1
Author: Vatine,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-10-21 08:53:25

4. ¿Usarías una utilidad tan ordenada en tus proyectos?

Lo más probable es que no. Creo que este es un caso de usar la herramienta adecuada para el trabajo. Hay algunas grandes respuestas aquí, tales como: 1579202 de Jeremy Stein. Recientemente "obtuve" expresiones regulares en un proyecto reciente y las encontré muy útiles tal como son, y cuando se comentan correctamente son comprensibles si conoces la sintaxis.

Creo que la parte de "conocer la sintaxis" es lo que desconcierta a la gente a las Expresiones Regulares, a aquellos que no entienden que parecen arcanos y crípticos, pero son una herramienta poderosa y en la Informática aplicada (por ejemplo, escribir software para ganarse la vida) siento que los profesionales inteligentes deberían y deberían ser capaces de aprender a usarlas y usarlas apropiadamente.

Como dicen: "Con un gran poder viene una gran responsabilidad."He visto a la gente utilizar expresiones regulares en todas partes para todo, pero utilizado juiciosamente por alguien que ha tomándose el tiempo para aprender la sintaxis a fondo, son increíblemente útiles; para mí, agregar otra capa de alguna manera derrotaría su propósito, o como mínimo le quitaría su poder.

Esta es mi propia opinión y puedo entender de dónde vienen las personas que desearían un marco como este, o que evitarían las expresiones regulares, pero me cuesta escuchar "Las expresiones regulares son malas" de aquellos que no se han tomado el tiempo para aprenderlas y tomar una decisión informada.

 1
Author: bn.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:02:48

Para hacer felices a todos (maestros de expresiones regulares y proponentes de la interfaz fluida), asegúrese de que la interfaz fluida pueda generar un patrón de expresiones regulares raw apropiado, y también tome una expresión regular usando un método de Fábrica y genere código fluido para ello.

 1
Author: John K,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-10-23 23:48:47

Lo que está buscando se puede encontrar aquí:. Es una expresión regular buillder que sigue el Patrón de diseño del Asistente

 1
Author: user1151546,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-08-27 07:09:08

Recientemente tuve esta misma idea.

Pensé en implementarlo yo mismo, pero luego encontré VerbalExpressions.

 1
Author: orlandocr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-06-30 21:58:18

Comparemos: He trabajado a menudo con (N)consultas ICriteria Hibernadas, que se pueden considerar una asignación Fluida a SQL. Estaba (y todavía estoy) entusiasmado con ellos, pero ¿hicieron las consultas SQL más legibles? No, más bien al contrario, pero aumentó otro beneficio:se hizo mucho más fácil construir declaraciones programáticamente, subclasificarlas y crear tus propias abstracciones, etc.

Lo que quiero decir es que usando una nueva interfaz para un lenguaje dado, si se hace bien, puede probar que vale la pena, pero no lo pienses demasiado bien. En muchos casos no será más fácil de leer (clases de caracteres de resta anidadas, Capturas en look-behind, si-ramificación para nombrar algunos conceptos avanzados que serán difíciles de combinar con fluidez). Pero en la misma cantidad de casos, los beneficios de una mayor flexibilidad superan la sobrecarga adicional de la complejidad de la sintaxis.

Para agregar a su lista de posibles enfoques alternativos y sacar esto del contexto de solo Java, considere el LINQ sintaxis. Esto es lo que podría parecer (un poco artificial) (from, where y {[3] } son palabras clave en LINQ):

// for ^str(aa|bb){3}
from part in mystring
where part startswith "str"
and part hasgroups "aa" or "bb" as first    /* "aa" or "bb" in group 'first' */
and part repeats first 3                    /* repeat group 'first' 3 times */
select part + "extra"                       /* can contain complete statement block */

Solo una idea aproximada, lo sé. Lo bueno de LINQ es que es comprobado por el compilador, una especie de lenguaje en un lenguaje. De forma predeterminada, LINQ también se puede expresar como sintaxis encadenada fluida, lo que lo hace, si está bien diseñado, compatible con otros lenguajes OO.

 0
Author: Abel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-10-23 02:39:27

Digo ir por ello, estoy seguro de que es divertido de implementar.

Sugiero usar un modelo de consulta (similar a jQuery, django dj), donde cada función devuelve un objeto de consulta, para que pueda encadenarlos.

any("a").some("b").one("@").some(chars).one(".").some(chars) //a*b+@\w+\.\w+

Donde chars está predefinido para ajustarse a cualquier carácter.

or se puede lograr mediante el uso de opciones:

any("a").choice("x", "z") // a(x|z)

El argumento para cada función puede ser una cadena u otra consulta. Por ejemplo, la variable chars mencionada anteriormente se puede definir como consulta:

//this one is ascii only
chars = raw("a-zA-Z0-9")

Y así, puede tener una función "raw" que acepta una cadena regex como entrada si se siente incómodo usar el sistema de consulta fluent.

En realidad, estas funciones solo pueden devolver expresiones regulares sin procesar, y encadenarlas es simplemente concatenar estas cadenas de expresiones regulares sin procesar.

any("a") ---> "a*"
raw("b+") ----> "b+"
one(".") ---> "\."
choice("a", "b") ----> (a|b)
 0
Author: hasen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-10-24 00:19:00

No estoy seguro de que reemplazar regexp con una API fluida traería mucho.

Tenga en cuenta que no soy un asistente de expresiones regulares (tengo que volver a leer el documento casi cada vez que necesito crear una expresión regular).

Una API fluida haría que cualquier expresión regular de complejidad media (digamos ~50 caracteres) sea aún más compleja de lo requerido y no sea más fácil de leer al final, aunque puede mejorar la creación de una expresión regular en un IDE, gracias a la finalización del código. Pero el mantenimiento del código generalmente representa un mayor costo que el desarrollo de código.

De hecho, ni siquiera estoy seguro de que sería posible tener una API lo suficientemente inteligente como para proporcionar realmente suficiente orientación al desarrollador al crear una nueva expresión regular, sin hablar de casos ambiguos, como se mencionó en una respuesta anterior.

Mencionaste un ejemplo de regexp para un RFC. Estoy 99% seguro (todavía hay 1% de esperanza;-)) de que cualquier API no haría que el ejemplo sea más simple, pero por el contrario eso solo lo haría más complejo de leer! Eso es un ejemplo típico donde no desea utilizar regexp de todos modos!

Incluso con respecto a la creación de expresiones regulares, debido al problema de los patrones ambiguos, es probable que con una API fluida, nunca llegaría con la expresión correcta la primera vez, sino que tendría que cambiar varias veces hasta obtener lo que realmente desea.

No se equivoquen, me encantan las interfaces fluidas; he desarrollado algunas bibliotecas que las usan, y uso varias bibliotecas de terceros basadas en ellas (por ejemplo, FEST para Java prueba). Pero no creo que puedan ser el martillo de oro para cualquier problema.

Si consideramos Java exclusivamente, creo que el principal problema con las expresiones regulares es el escape necesario de las barras invertidas en constantes de cadena de Java. Ese es un punto que hace que sea increíblemente difícil crear y entender regexp en Java. Por lo tanto, el primer paso para mejorar Java regexp sería, para mí, un cambio de lenguaje, a la Groovy , donde las constantes de cadena no necesitan escapar diagonal.

Hasta ahora esa sería mi única propuesta para mejorar regexp en Java.

 0
Author: jfpoilpret,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-10-25 01:34:01