java - interfaces - Diseño de una interfaz alternativa(¿fluida?) Para expresiones regulares
interfaz grafica para netbeans (18)
En respuesta a la última parte de la pregunta (para Kudos)
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
Acabo de ver una gran expresión regular para Java que me hizo pensar un poco sobre la capacidad de mantenimiento de las expresiones regulares en general. Creo que la mayoría de las personas, excepto algunos traficantes de perras rudos, estarían de acuerdo en que las expresiones regulares no se pueden mantener.
Estaba pensando en cómo podría arreglarse 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 aún es bastante legible para cualquier desarrollador mediocre con talento. Sin embargo, piense en esas expresiones espeluznantes que llenan dos o más líneas con 80 caracteres cada una. Claro, la interfaz fluida (detallada) 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:
¿Conoces algún enfoque similar a las expresiones regulares?
¿Está de acuerdo en que este enfoque podría ser mejor que usar cadenas simples?
¿Cómo diseñarías la API?
¿Usarías una utilidad tan prolija en tus proyectos?
¿Crees que sería divertido implementarlo? ;)
EDITAR: Imagine que podría haber métodos que están en un nivel más alto que las construcciones simples que no todos tenemos de expresiones regulares, por ejemplo
// matches [email protected] - think of it as reusable expressions
Pattern p = string{"a").anyTimes().string("b@").domain().compile();
EDITAR - breve resumen de los comentarios:
RegexBuddy : gaste 30 EUR para hacer que su código sea legible (¡wtf?! La existencia pura de un producto así demuestra que mi tesis es correcta: las expresiones regulares como las conocemos hoy en día son una cosa mala (tm))
El enfoque de Martin Fowler (que aún está lejos de ser perfecto)
Es interesante leer que la mayoría de las personas piensan que las expresiones regulares están aquí para quedarse, aunque se necesitan herramientas para leerlas e individuos inteligentes para pensar en formas de mantenerlas. Si bien no estoy seguro de que una interfaz fluida sea la mejor manera de hacerlo, estoy seguro de que algunos ingenieros inteligentes: ¿nosotros? ;) - debería dedicar algo de tiempo a convertir las expresiones regulares en algo del pasado; basta con que hayan estado con nosotros durante 50 años, ¿no cree?
BOUNTY ABIERTO
La recompensa se otorgará 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 para el primero que puede traducirlo - RegexBuddies permitió (es de un proyecto de 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 es RFC822 (ver ex-parrot.com ), no 5322 , aunque no estoy seguro de si hay alguna diferencia, si es así, ex-parrot.com próxima felicitación adicional para que un parche encaje en 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*)";
Este es un concepto intrigante, pero como se presenta hay algunos defectos.
Pero las primeras respuestas a las preguntas clave formuladas:
Ahora mis preguntas:
1. ¿Conoces algún enfoque similar a las expresiones regulares?
Ninguno que no haya sido mencionado ya. Y los que descubrí leyendo las preguntas y respuestas.
2. ¿Está de acuerdo en que este enfoque podría ser mejor que usar cadenas simples?
Si funciona como se anuncia, definitivamente hará 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 prolija en tus proyectos?
Indeciso. No tengo ningún problema en trabajar con la versión actual de las expresiones crípticas regularmente. Y necesitaría una herramienta para convertir expresiones regulares existentes a la versión de idioma fluido.
5. ¿Crees que sería divertido implementarlo? ;)
Disfrutaría trabajando en el nivel superior de cómo, escribiendo 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 lidiaría con ellos.
Estructura poco clara.
Su ejemplo parece crear una expresión regular concatenando en 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á que todos los métodos actúan sobre los objetos del Patrón y los devuelven.
Edición: Parece que he usado las siguientes convenciones a lo largo. Así que los he aclarado y los muevo aquí arriba.
Métodos de instancia: aumento de patrón. Ej .: captura, repetición, mirar alrededor de las afirmaciones.
Operadores: orden de operaciones. alternancia, concatenación
Constantes: clases de caracteres, límites (en lugar de / w, $, / b, etc.)
¿Cómo se manejará la captura / agrupamiento?
La captura es una gran parte de las expresiones regulares.
Veo que cada objeto de patrón se almacena internamente como un grupo. (?: patrón) en términos de Perl. Permitiendo que los tokens de patrones se mezclen y mezclen fácilmente sin interferir con otras piezas.
Espero que la captura se realice como un método de instancia en un patrón. Tomando una variable para almacenar la cadena [s] correspondiente en.
pattern.capture(variable)
almacenaría patrón en variable. En el caso de que la captura forme parte de una expresión que se comparará varias veces, la variable debe contener una serie de cadenas de todas las coincidencias para el patrón.
Las lenguas fluidas pueden ser muy ambiguas.
Las lenguas fluidas no son adecuadas para la naturaleza recursiva de las expresiones regulares. Por lo tanto, se debe tener en cuenta el orden de las operaciones. Solo encadenar métodos no permite expresiones regulares muy complejas. Exactamente la situación en la que tal herramienta sería útil.
Hace
Pattern pattern = string("a").anyTimes().or().string("b").times(2,5).compile();
producir /a*|b{2,5}/
o /(a*|b){2,5}/
?
¿Cómo manejaría tal esquema la alternancia anidada? Por ejemplo: /a*|b(c|d)|e/
Veo tres formas de manejar la alternancia en expresiones regulares.
- Como operador:
pattern1 or pattern2 => pattern # /pattern1|pattern2/
- Como método de clase:
Pattern.or( pattern1, pattern2[, pattern3]*) => pattern # /pattern1|patern2|patern3|...|/
- Como método de instancia:
pattern1.or(pattern2) => pattern # /pattern1|patern2/
Yo manejaría la concatenación de la misma manera.
- Como operador:
pattern1 + pattern2 => pattern # /pattern1pattern2/
- Como método de clase:
Pattern.concatenate( pattern1, pattern2[, pattern3]*) => pattern # /pattern1patern2patern3.../
- Como método de instancia:
pattern1.then(pattern2) => pattern # /pattern1patern2/
Cómo extender para patrones comúnmente usados
El esquema propuesto usaba .domain()
que parece ser una expresión regular. 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 anular la clase para agregar métodos para los patrones de uso común.
Esto se aborda en mi sugerencia de tratar cada pieza como un objeto. Se puede crear un objeto de patrón para cada expresión regular de uso común como, por ejemplo, hacer coincidir un dominio. Teniendo en cuenta mis pensamientos anteriores acerca de la captura, no sería difícil garantizar que la captura funcione 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.
Ancho cero mirar alrededor de las afirmaciones
Ampliando mis pensamientos de que todas las piezas deben estar agrupadas implícitamente. Mire a su alrededor las afirmaciones no debería ser demasiado difícil también con un método de instancia.
pattern.zeroWidthLookBehind()
produciría (?<patten)
.
Cosas que aún deben ser consideradas.
- Backreferences: Esperemos que no sea demasiado difícil con la captura mencionada mencionada anteriormente
- Cómo implementarlo realmente. No he pensado demasiado en lo interno. Es donde la verdadera magia va a suceder.
- Traducción: Realmente debería haber una herramienta traducida hacia y desde las expresiones regulares clásicas (por ejemplo, dialecto Perl) y el nuevo esquema. La traducción del nuevo esquema podría ser una parte del paquete.
Juntándolo todo, 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 plan se basa en gran medida en el enfoque de Martin Fowler en uso. Aunque no tenía la intención de que las cosas salieran de esta manera, definitivamente hace que el uso de ese sistema sea más fácil de mantener. También aborda un problema o dos con el enfoque de Fowler (orden de captura).
Hay una biblioteca de expresiones regulares fluida para .NET.
La respuesta corta, para mí, es que, una vez que llegue a las expresiones regulares (u otro tipo de coincidencia de patrones que haga lo mismo) que sea lo suficientemente largo como para causar un problema ... probablemente debería 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 verbosa, pero no demasiado larga; es legible Pero también lo es la expresión regular de algo tan largo.
Para una expresión regular de tamaño mediano, una interfaz fluida se vuelve difícil de manejar; El tiempo suficiente para que sea difícil, si no imposible, leer.
Para una expresión regular larga (es decir, la dirección de correo electrónico uno), 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.
Martin Fowler sugiere otra estrategia . Es decir, tomar partes significativas de la expresión regular y reemplazarlas por variables. Utiliza 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
Mi propio intento humilde se puede encontrar en GitHub . Aunque no creo que valga la pena usarlo para expresiones simples, ofrece un par de ventajas aparte de la mejora de la legibilidad:
- Se encarga de emparejar los brackets.
- Maneja el escape de todos los personajes ''especiales'' que pueden conducir rápidamente a la barra inversa del infierno
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 una más complicada (que más o menos valida las direcciones de correo electrónico):
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()
)
);
Puede ser un poco más fácil para alguien sin experiencia en expresiones regulares, pero después de que alguien aprenda su sistema, no podrá leer una expresión regular en otro lugar.
Además, creo que su versión es más difícil de leer para un experto en expresiones regulares.
Recomendaría anotar la expresión regular como esta:
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 regex al mismo tiempo. Además, los comentarios se pueden adaptar a la situación para explicar las reglas comerciales detrás de la expresión regular en lugar de solo la estructura.
Además, una herramienta como RegexBuddy puede tomar su expresión regular y traducirla en:
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}»
Respuesta corta: Lo he visto acercarse desde un ángulo de alineación y compilación, lo que creo que es algo a tener en cuenta 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 firewall a velocidades de 20 GB / seg en los enrutadores de la red en lugar de utilizar ciclos valiosos de servidores o procesadores. La mayoría de las aplicaciones antivirus, antispam o cortafuegos son un conjunto de expresiones regulares en el núcleo.
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 que nuestros clientes los ayuden a mantener y ajustar sus expresiones.
De vuelta a la pregunta del OP, en lugar de definir una sintaxis completamente nueva, escribiría una interpolación (lo siento, la nuestra es propietaria), cortar y pegar regex''s que descomponga el regex legacy y dé como resultado "fluidez en inglés" para que alguien lo comprenda mejor. También agregaría verificaciones de rendimiento relativo y sugerencias para modificaciones comunes.
¿Cómo diseñarías la API?
Tomaría 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()
Use 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 creo que es más fácil comprender la jerarquía / estructura del patrón. Cada método podría aceptar una cadena o un fragmento de patrón como primer argumento.
¿Conoces algún enfoque similar a las expresiones regulares?
No de la mano, no.
¿Está 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 prolija en tus proyectos?
Posiblemente, ya que se ha demostrado / estable ... convertirlo en un proyecto de utilidad más grande como Apache Commons podría ser una ventaja.
¿Crees que sería divertido implementarlo? ;)
+1
¿Conoces algún enfoque similar a las expresiones regulares?
No, excepto por la respuesta anterior.
¿Está 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 la lógica compleja sea más clara.
¿Cómo diseñarías la API?
Convierta cada construcción en un nombre de método y permita llamadas de función anidadas para que sea muy fácil tomar una cadena y sustituir nombres de métodos en ella.
Creo que la mayor parte del valor estará en definir una biblioteca robusta de funciones de utilidad, como hacer coincidir "correos electrónicos", "números de teléfono", "líneas que no contienen X", etc. que se pueden personalizar.
¿Usarías una utilidad tan prolija en tus proyectos?
Tal vez, pero probablemente solo para las más largas, donde sería más fácil depurar las llamadas a funciones que la depuración de la edición de cadenas, o donde haya una buena función de utilidad lista para usar.
¿Crees que sería divertido implementarlo? ;)
¡Por supuesto!
4. ¿Usarías una utilidad tan prolija en tus proyectos?
Probablemente no lo haría. Creo que este es un caso de usar la herramienta adecuada para el trabajo. Hay algunas respuestas geniales aquí 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 convierte a las personas en expresiones regulares, a aquellas que no entienden que se ven arcanas y crípticas, pero son una herramienta poderosa y en informática aplicada (por ejemplo, software de escritura para ganarse la vida) Siento que los profesionales inteligentes deberían y deberían poder aprender a usarlos y usarlos adecuadamente.
Como dicen "Con gran poder viene una gran responsabilidad". He visto personas que usan expresiones regulares en todas partes para todo, pero que alguien que se ha tomado el tiempo de aprender a fondo la sintaxis las ha usado con prudencia, son increíblemente útiles; para mí, agregar otra capa sería de alguna manera derrotar a su propósito, o como mínimo quitaría su poder.
Esto es solo mi 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 mucho escuchar "Expresiones regulares son malas" de aquellos que no se toman el tiempo. Para aprenderlos y tomar una decisión informada.
No estoy seguro de que reemplazar la expresión regular con una API fluida traiga 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 necesario 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 costo mayor que el desarrollo del código.
De hecho, ni siquiera estoy seguro de que sea posible tener una API lo suficientemente inteligente como para proporcionar una orientación suficiente al desarrollador al crear una nueva expresión regular, sin hablar de casos ambiguos, como se mencionó en una respuesta anterior.
Usted mencionó un ejemplo de expresión regular para un RFC. Estoy seguro al 99% (todavía hay 1% de esperanza ;-)) de que cualquier API no haría ese ejemplo más simple, pero a la inversa, ¡eso solo haría que sea más complejo de leer! ¡Ese es un ejemplo típico en el que no quieres usar 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 vendría con la expresión correcta la primera vez, pero tendría que cambiar varias veces hasta que obtenga lo que realmente desea.
No me equivoque, me encantan las interfaces fluidas; He desarrollado algunas bibliotecas que las utilizan, y utilizo varias bibliotecas de terceros basadas en ellas (por ejemplo, FEST para pruebas de Java). Pero no creo que puedan ser el martillo de oro para ningún problema.
Si consideramos Java exclusivamente, creo que el principal problema con las expresiones regulares es el escape necesario de las barras invertidas en las constantes de cadena de Java. Ese es un punto que hace que sea increíblemente difícil crear y entender la expresión regular en Java. Por lo tanto, el primer paso para mejorar la expresión regular de Java sería, para mí, un cambio de idioma, a la Groovy , donde las constantes de cadena no necesitan escapar de las barras invertidas.
Hasta ahora, esa sería mi única propuesta para mejorar la expresión regular en Java.
Para hacer felices a todos (expertos en expresiones regulares y defensores de la interfaz de fluidos), asegúrese de que la interfaz de fluidos pueda generar un patrón de expresiones regulares en bruto apropiado, y también tome una expresión regular regular utilizando un método de Fábrica y genere un código de fluido para ello.
Yo digo "adelante", estoy seguro de que es divertido de implementar.
Sugiero usar un modelo de consulta (similar a jQuery, django ORM), 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 adaptarse a cualquier personaje.
or
se puede lograr mediante el uso de opciones:
any("a").choice("x", "z") // a(x|z)
El argumento de cada función puede ser una cadena u otra consulta. Por ejemplo, la chars
variable mencionada anteriormente se puede definir como una consulta:
//this one is ascii only
chars = raw("a-zA-Z0-9")
Y así, puede tener una función "en bruto" que acepta una cadena de expresiones regulares como entrada si se siente incómodo de usar el sistema de consulta fluido.
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)
Comparemos: he trabajado a menudo con (N) consultas de Hibernate ICriteria, que pueden considerarse una asignación fluida a SQL. Estaba (y sigo) entusiasmado con ellos, pero ¿hicieron que las consultas de SQL fueran más legibles? No, más bien al contrario, pero surgió otro beneficio: se hizo mucho más fácil crear sentencias mediante programación, crear subclases y crear sus propias abstracciones, etc.
A lo que me refiero es que usar una nueva interfaz para un idioma dado, si se hace bien, puede valer la pena, pero no lo consideres demasiado. En muchos casos, no será más fácil de leer (clases de caracteres de resta anidadas, capturas en look-behind, if-branching para nombrar algunos conceptos avanzados que serán difíciles de combinar con fluidez). Pero en tantos 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 la sintaxis de LINQ. Esto es lo que podría ser similar (un poco artificial) ( from
, where
yselect
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 */
Sólo una idea aproximada, lo sé. Lo bueno de LINQ es que está comprobado por el compilador, una especie de lenguaje en un idioma. Por defecto, LINQ también puede expresarse como una sintaxis encadenada fluida, lo que lo hace, si está bien diseñado, compatible con otros idiomas OO.
Hace poco tuve esta misma idea .
Pensé en implementarlo yo mismo, pero luego encontré VerbalExpressions .
Lo que se busca se puede encontrar here: . Es un buillder de expresiones regulares que sigue el patrón de diseño del asistente.
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, relativamente poco ambiguo y está bastante bien adoptado.
PUEDE ser que una mejor representación sería un diagrama de transición de estado, pero probablemente sea difícil de usar en el código fuente.
Una posibilidad sería construirlo a partir de una variedad de objetos de contenedor y combinador.
Algo a lo largo de la línea de lo siguiente (dejar esto de pseudocódigo a un idioma 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 en forma arbitraria 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 FSM simple para un análisis completo. Sin embargo, no creo que clasifique erróneamente una dirección válida como no válida.
Debe corresponder a [^ @] + @ ([a-zA-Z0-9 -] +.) +. ([A-zA-Z0-9 -] +)