!rm`.*$
Con una sola expresión regular, Retina se ejecuta en modo Match. Esto normalmente solo imprime el número de coincidencias, pero con !
esto lo configuramos para imprimir las coincidencias reales en su lugar (separadas por avances de línea).
La expresión regular real es meramente .*$
. .*
coincide con cualquier línea (potencialmente vacía), porque .
puede coincidir con cualquier carácter, excepto los avances de línea. Llegaré al $
en un minuto.
¿Cómo hacemos que imprima los partidos al revés? Al hacer uso del modo de coincidencia de derecha a izquierda de .NET, activado con r
. Esto significa que el motor regex comienza al final de la cadena cuando busca coincidencias y funciona al revés.
Finalmente, m
hace que la $
coincidencia sea el final de una línea en lugar del final de la cadena. ¿Por qué necesitamos eso? El problema es que .*
genera coincidencias extrañas. Considere la sustitución de expresiones regulares
s/a*/$0x/
aplicado a la entrada baaababaa
. Pensarías que esto cedería baaaxbaxbaax
, pero en realidad te da baaaxxbaxxbaaxx
. ¿Por qué? Porque después de hacer coincidir aaa
el cursor del motor está entre el a
y el b
. Ahora ya no puede coincidir con a
s, pero a*
también está satisfecho con una cadena vacía. Esto significa que, después de cada partido, obtienes otro partido vacío.
No queremos eso aquí, porque introduciría líneas vacías adicionales, por lo que descartamos esas coincidencias extrañas (que se encuentran al comienzo de las líneas, debido al modo de derecha a izquierda) al requerir que las coincidencias incluyan el final de la línea.
tac
es un poco extraño cuando se trata de avances de línea finales. Se transformaa\nb\n
(avance de línea final) enb\na\n
ya\nb
(sin avance de línea final) enba\n
. ¿Es así como se supone que debe comportarse nuestro código?