regulares regular google expresiones expresion especiales espacio ejemplos cualquier caracteres caracter blanco basicas alfanumerico regex language-design regex-greedy

regex - google - expresiones regulares ejemplos



¿Por qué las expresiones regulares son codiciosas por defecto? (6)

Parecería que un caso de uso típico sería no codicioso.

Quiero dejar claro que esto es incorrecto, a menos que "caso de uso típico" signifique hackeo de HTML.

Un ejemplo fácil son los analizadores léxicos para lenguajes de programación. Simplemente no quieres

foo = 42

para ser interpretado como 3 variables, seguido de un signo igual, seguido de 2 números. Por el contrario, normalmente esperas que tu analizador considere las coincidencias más largas posibles.

Antes del advenimiento de HTML, nosotros, los mayores, hemos vivido durante décadas con expresiones regulares codiciosas, y nos fue bien. Incluso hoy en día no uso los no codiciosos en el 99% de todos los casos, hay que reconocer que soy demasiado vago para buscar la sintaxis, pero también porque las ocasiones en las que rara vez se puede escribir un codicioso. Por ejemplo, para hacer coincidir una cadena:

"(//"|[^"])*"

Parece que esta es una gran fuente de confusión para los principiantes que escriben expresiones regulares, pueden causar problemas de rendimiento ocultos, y parece que un caso de uso típico no sería codicioso.

¿Es esto solo por razones heredadas (fue la forma en que se hizo por primera vez, y cada implementación las copia), o existe una razón para ello?



Bueno, es importante que las computadoras se comporten de manera predecible siempre que sea posible. Por lo tanto, el comportamiento correcto debe seguir una regla simple, como el codicioso emparejamiento, para que al menos los programadores experimentados puedan predecir el resultado de un fragmento de código.

En cuanto a si un caso de uso típico debería ser no codicioso, ¿qué ocurre con lo siguiente? Supongamos que tengo un archivo con entradas como foo1909, bar3939, baz3331 y solo quiero extraer estos números. Parece bastante natural escribir (/ d *) como la expresión regular para esto.

Podría decir que es tan fácil escribir (/ d *) / D o lo que sea, pero básicamente siempre es así que el programador puede ser más explícito y menos ambiguo. Ya que queríamos un comportamiento predeterminado que fuera 100% predecible, y trivial para calcular en la cabeza, me parece razonable.


El verdadero problema aquí es el operador de cierre Kleene (estrella); para todo lo demás en una expresión regular, la coincidencia más larga es la misma que la coincidencia más corta.

Cuando lo piensas en esos términos, te das cuenta de que las herramientas más modernas se dan cuenta de que necesitas ambas. Me levanto tarde, así que solo puedo pensar en dos ejemplos:

  • Tanto ksh como bash proporcionan formas de "coincidencia más larga" y "coincidencia más corta" de la mayoría de los operadores especiales que modifican las variables.

  • Las expresiones regulares de Lua incluyen * para el cierre más largo de Kleene y para el cierre más corto de Kleene. Este siempre me muerde cuando olvido escapar de un signo literal.

Sería interesante volver al trabajo original de Kleene y ver si eso podría haber influido en las herramientas tempranas hacia la coincidencia más larga.


En el caso del rendimiento, los cuantificadores perezosos no siempre son más rápidos debido al retroceso: http://blog.stevenlevithan.com/archives/greedy-lazy-performance

En cuanto al diseño real, honestamente no puedo decir por qué los cuantificadores son codiciosos por defecto, pero me pregunto qué personaje de control se habría utilizado para hacer un cuantificador codicioso en lugar de perezoso. Yo no pienso Lo habría cortado :-)