Diferencia entre \ A \ z y ^ $ en expresiones regulares de Ruby

196

En la documentación leí:

Use \ A y \ z para hacer coincidir el inicio y el final de la cadena, ^ y $ coinciden con el inicio / final de una línea.

Voy a aplicar una expresión regular para verificar el nombre de usuario (o el correo electrónico es el mismo) enviado por el usuario. ¿Con qué expresión debo usar validates_format_ofen el modelo? No puedo entender la diferencia: siempre he usado ^ y $ ...

collimarco
fuente

Respuestas:

226

Si depende de la expresión regular para la validación, siempre desea usar \Ay \z. ^y $solo coincidirá hasta un carácter de nueva línea, lo que significa que podrían usar un correo electrónico como [email protected]\n<script>dangerous_stuff();</script>y aún así validarlo, ya que la expresión regular solo ve todo antes del \n.

Mi recomendación sería eliminar completamente las nuevas líneas de un nombre de usuario o correo electrónico de antemano, ya que no hay una razón legítima para ello. Entonces puede usar con seguridad ya \A \zsea ^ $.

Luke
fuente
13
@Ragmaanir tiene razón, ¡debería ser con letra minúscula en \zlugar de \Z!
Petr
10
+1 ¡Gracias! Aunque tendría que estar en desacuerdo con su recomendación: A) No agregue trabajo / procesamiento innecesario si hay un conjunto apropiado, y B) especialmente si le permite permanecer flojo para distinguir entre los dos. Es posible que no siempre esté en condiciones de manipular cadenas, solo a Regex, ¡así que guarde el correcto en la memoria y sepa la diferencia!
dooleyo
1
No entendí el ejemplo con cosas peligrosas porque en cualquiera de los casos uno podría incluir cosas peligrosas en la cadena, con o sin nuevas líneas sería un exploit que debería solucionarse con la desinfección y validación html.
Jayr Motta
2
@JayrMotta lo que muestra la demostración es que las cosas peligrosas pasarían por alto por completo su verificación de expresiones regulares . Por lo tanto, incluso si estaba buscando cosas peligrosas en su expresión regular, se omitiría si solía $verificar el "final de la cadena" en lugar de \z.
Doctor Blue
177

De acuerdo con Pickaxe :

^ Coincide con el comienzo de una línea.

$ Coincide con el final de una línea.

\A Coincide con el comienzo de la cadena.

\z Coincide con el final de la cadena.

\Z Coincide con el final de la cadena a menos que la cadena termine con a "\n", en cuyo caso coincide justo antes de "\n".

Entonces, use \Ay minúsculas \z. Si usa a \Zalguien podría colarse en un personaje de nueva línea. Creo que esto no es peligroso, pero podría arruinar algoritmos que suponen que no hay espacios en blanco en la cadena. Dependiendo de sus restricciones de expresión regular y longitud de cadena, alguien podría usar un nombre invisible con solo un carácter de nueva línea.

La implementación de JavaScript de Regex trata \Acomo un literal 'A'( ref ). Así que ten cuidado y prueba.

Ragmaanir
fuente
16

El inicio y el final de una cadena pueden no ser necesariamente lo mismo que el inicio y el final de una línea. Imagínese si usara lo siguiente como su cadena de prueba:

mi
nombre
es
andrew

Tenga en cuenta que la cadena tiene muchas líneas: los caracteres ^y le $permiten hacer coincidir el principio y el final de esas líneas (básicamente, tratan el \ncarácter como un delimitador) \Ay le \Zpermiten hacer coincidir el principio y el final de toda la cadena.

Andrew Hare
fuente
1
La mejor respuesta en mi opinión. "básicamente tratar al personaje \ n como un delimitador" realmente me ayudó a entender, gracias.
Flyout91
11

Diferencia por ejemplo

  1. /^foo$/coincide con cualquiera de los siguientes, /\Afoo\z/no:
whatever1
foo
whatever2
foo
whatever2
whatever1
foo
  1. /^foo$/y /\Afoo\z/todos coinciden con lo siguiente:
foo
Chun Yang
fuente