Différence entre \ A \ z et ^ $ dans les expressions régulières Ruby

199

Dans la documentation, j'ai lu:

Utilisez \ A et \ z pour correspondre au début et à la fin de la chaîne, ^ et $ correspondent au début / à la fin d'une ligne.

Je vais appliquer une expression régulière pour vérifier le nom d'utilisateur (ou l'e-mail est le même) soumis par l'utilisateur. Quelle expression dois-je utiliser validates_format_ofdans le modèle? Je ne comprends pas la différence: j'ai toujours utilisé ^ et $ ...

collimarco
la source

Réponses:

231

Si vous dépendez de l'expression régulière pour la validation, vous souhaitez toujours utiliser \Aet \z. ^et $ne correspondra que jusqu'à un caractère de nouvelle ligne, ce qui signifie qu'ils pourraient utiliser un e-mail comme [email protected]\n<script>dangerous_stuff();</script>et le faire valider, puisque l'expression régulière ne voit que tout avant le \n.

Ma recommandation serait simplement de supprimer complètement les nouvelles lignes d'un nom d'utilisateur ou d'un e-mail au préalable, car il n'y a pratiquement aucune raison légitime pour une. Ensuite, vous pouvez utiliser en toute sécurité SOIT \A \zou ^ $.

Luke
la source
13
@Ragmaanir a raison, ça devrait être avec une petite lettre \zau lieu de \Z!
Petr
11
+1 Merci! Bien que je devrais être en désaccord avec votre recommandation: A) N'ajoutez pas de travail / traitement inutile s'il y a un fourre-tout approprié, et B) surtout pas si cela vous permet de rester paresseux pour faire la distinction entre les deux. Vous n'êtes peut-être pas toujours en mesure de manipuler des chaînes, uniquement avec Regex, alors mettez la bonne en mémoire et connaissez la différence!
dooleyo
1
Je n'ai pas compris l'exemple avec des trucs dangereux parce que dans les deux cas, on pouvait inclure des trucs dangereux dans la chaîne, avec ou sans nouvelles lignes, ce serait un exploit qui devrait être corrigé avec un nettoyage et une validation html.
Jayr Motta
2
@JayrMotta ce que la démonstration montre, c'est que les trucs dangereux contourneraient complètement votre vérification regex . Ainsi, même si vous recherchiez des éléments dangereux dans votre expression régulière, elle serait contournée si vous aviez l'habitude $de vérifier "fin de chaîne" au lieu de \z.
Doctor Blue
182

Selon Pickaxe :

^ Correspond au début d'une ligne.

$ Correspond à la fin d'une ligne.

\A Correspond au début de la chaîne.

\z Correspond à la fin de la chaîne.

\Z Correspond à la fin de la chaîne sauf si la chaîne se termine par un "\n", auquel cas elle correspond juste avant le "\n".

Alors, utilisez \Aet minuscules \z. Si vous utilisez \Zquelqu'un pourrait se faufiler dans un caractère de nouvelle ligne. Ce n'est pas dangereux je pense, mais cela pourrait bousiller les algorithmes qui supposent qu'il n'y a pas d'espace blanc dans la chaîne. En fonction de votre expression régulière et de vos contraintes de longueur de chaîne, quelqu'un pourrait utiliser un nom invisible avec juste un caractère de nouvelle ligne.

L'implémentation de JavaScript de Regex est traitée \Acomme un littéral 'A'( ref ). Alors surveillez-vous et testez.

Ragmaanir
la source
16

Le début et la fin d'une chaîne ne sont pas nécessairement la même chose que le début et la fin d'une ligne. Imaginez si vous utilisiez ce qui suit comme chaîne de test:

mon
nom
est
Andrew

Notez que la chaîne contient de nombreuses lignes - les caractères ^et $vous permettent de faire correspondre le début et la fin de ces lignes (en traitant essentiellement le \ncaractère comme un délimiteur) \Aet \Zvous permettent de faire correspondre le début et la fin de la chaîne entière.

Andrew Hare
la source
1
Meilleure réponse à mon avis. "traiter essentiellement le caractère \ n comme un délimiteur" m'a vraiment aidé à comprendre, merci.
Flyout91
12

Différence par exemple

  1. /^foo$/correspond à l'un des éléments suivants, /\Afoo\z/ne correspond pas:
whatever1
foo
whatever2
foo
whatever2
whatever1
foo
  1. /^foo$/et /\Afoo\z/tous correspondent à ce qui suit:
foo
Chun Yang
la source