web-dev-qa-db-fra.com

Quelle est la différence entre\z et\Z dans une expression régulière et quand et comment l'utiliser?

De http://Java.Sun.com/j2se/1.5.0/docs/api/Java/util/regex/Pattern.html :

\Z  The end of the input but for the final terminator, if any
\z  The end of the input

Mais qu'est-ce que cela signifie en pratique? Pouvez-vous me donner un exemple lorsque j'utilise soit le\Z ou le\z.

Dans mon test, je pensais que "StackOverflow\n".matches("StackOverflow\\z") renverrait true et que "StackOverflow\n".matches("StackOverflow\\Z") renverrait false. Mais en réalité, les deux retournent faux. Où est l'erreur?

31
Mister M. Bean

Même si \Z et $ ne correspondent qu'à la fin de la chaîne (lorsque L'option pour que le curseur et le dollar correspondent aux sauts de ligne intégrés est Off), il existe une exception. Si la chaîne se termine par un saut de ligne, alors \Z et $ seront identiques à la position précédant ce saut de ligne, plutôt qu'à la toute fin de la chaîne. 

Cette "amélioration" a été introduite par Perl et est copiée par beaucoup de regex saveurs, y compris Java, .NET et PCRE. En Perl, lors de la lecture d'une ligne à partir d'un fichier, la chaîne résultante se termine par un saut de ligne. En train de lire une ligne d'un fichier avec le texte "joe" donne la chaîne joe\n . Lorsqu'ils sont appliqués à cette chaîne, ^[a-z]+$ et \A[a-z]+\Z seront tous les deux correspond à "joe".

Si vous voulez seulement une correspondance à la toute fin de la chaîne, utilisez \z (z minuscule au lieu de Z majuscule). \A[a-z]+\z ne pas correspondre à joe\n. \z correspond après le saut de ligne, ce qui ne correspond pas par la classe de personnage.

http://www.regular-expressions.info/anchors.html

La façon dont j'ai lu cette "StackOverflow\n".matches("StackOverflow\\z") devrait retourner false car votre modèle n'inclut pas la nouvelle ligne.

"StackOverflow\n".matches("StackOverflow\\z\\n") => false
"StackOverflow\n".matches("StackOverflow\\Z\\n") => true
30
Jakob Kruse

Je viens de vérifier. On dirait que lorsque Matcher.matches () est appelé (comme dans votre code, en coulisse),\Z se comporte comme\z. Toutefois, lorsque Matcher.find () est appelé, il se comporte différemment que prévu. Les valeurs suivantes sont vraies:

Pattern p = Pattern.compile("StackOverflow\\Z");
Matcher m = p.matcher("StackOverflow\n");
System.out.println(m.find());

et si vous remplacez\Z par\z cela retourne faux.

Je trouve cela un peu surprenant ...

5
Eyal Schneider

\Z est identique à $, il correspond à la fin de la chaîne, celle-ci pouvant être suivie d'un saut de ligne.

 enter image description here  enter image description here

\z correspond à la fin de la chaîne, ne peut pas être suivi d'un saut de ligne.

 enter image description here  enter image description here

0
code4j

Comme Eyal l'a dit, cela fonctionne pour find () mais pas pour matches ().

Cela a du sens. L'ancre\Z elle-même correspond bien à la position juste avant le terminateur final eol, mais l'expression régulière dans son ensemble ne correspond pas, car, dans son ensemble, elle doit correspondre au texte entier mis en correspondance et rien ne correspond au terminateur. (Le\Z correspond à la position droite avant le terminateur, ce qui n'est pas la même chose.)

Si vous avez fait _"StackOverflow\n".matches("StackOverflow\\Z.*"), tout devrait bien se passer.

0
Avi

Je pense que le problème principal est le comportement inattendu de matches(): toute correspondance doit consommer toute la chaîne d’entrée . Vos deux exemples échouent car les expressions rationnelles ne consomment pas le saut de ligne à la fin de la chaîne. Les ancres n'ont rien à voir avec ça.

Dans la plupart des langues, une correspondance d'expression régulière peut survenir n'importe où, consommant toute, certaines ou aucune des chaînes d'entrée. Et Java a une méthode, Matcher#find(), qui exécute ce type de correspondance traditionnel. Cependant, les résultats sont à l'opposé de ce que vous aviez prévu:

Pattern.compile("StackOverflow\\z").matcher("StackOverflow\n").find()  //false
Pattern.compile("StackOverflow\\Z").matcher("StackOverflow\n").find()  //true

Dans le premier exemple, le \z doit correspondre à la fin de la chaîne, mais le saut de ligne de fin le gêne. Dans le second cas, le \Z correspond avant le saut de ligne, qui se trouve à la fin de la chaîne.

0
Alan Moore