web-dev-qa-db-fra.com

Java regex: Lookahead négatif

J'essaie de créer deux expressions régulières qui correspondent aux URI. Ces URI sont au format: /foo/someVariableData Et /foo/someVariableData/bar/someOtherVariableData

J'ai besoin de deux regex. Chacun doit correspondre à l'un mais pas à l'autre.

Les expressions rationnelles que j'ai inventées à l'origine sont: /foo/.+ Et /foo/.+/bar/.+ Respectivement.

Je pense que le deuxième regex est très bien. Il ne correspondra qu'à la deuxième chaîne. Le premier regex, cependant, correspond aux deux. J'ai donc commencé à jouer (pour la première fois) avec un lookahead négatif. J'ai conçu l'expression rationnelle /foo/.+(?!bar) et mis en place le code suivant pour le tester

public static void main(String[] args) {
    String shouldWork = "/foo/abc123doremi";
    String shouldntWork = "/foo/abc123doremi/bar/def456fasola";
    String regex = "/foo/.+(?!bar)";
    System.out.println("ShouldWork: " + shouldWork.matches(regex));
    System.out.println("ShouldntWork: " + shouldntWork.matches(regex));
}

Et, bien sûr, les deux se résolvent en true.

Quelqu'un sait ce que je fais mal? Je n'ai pas besoin d'utiliser nécessairement l'anticipation négative, j'ai juste besoin de résoudre le problème, et je pense que l'anticipation négative pourrait être une façon de le faire.

Merci,

34
Cody S

Essayer

String regex = "/foo/(?!.*bar).+";

ou peut-être

String regex = "/foo/(?!.*\\bbar\\b).+";

pour éviter les échecs sur des chemins comme /foo/baz/crowbars ce que je suppose que vous voulez que cette expression régulière corresponde.

Explication: (sans les doubles barres obliques inverses requises par Java strings)

/foo/ # Match "/foo/"
(?!   # Assert that it's impossible to match the following regex here:
 .*   #   any number of characters
 \b   #   followed by a Word boundary
 bar  #   followed by "bar"
 \b   #   followed by a Word boundary.
)     # End of lookahead assertion
.+    # Match one or more characters

\b, "l'ancre de limite de mot", correspond à l'espace vide entre un caractère alphanumérique et un caractère non alphanumérique (ou entre le début/la fin de la chaîne et un caractère alnum). Par conséquent, il correspond avant le b ou après le r dans "bar", mais il ne correspond pas entre w et b dans "crowbar".

Protip: Jetez un oeil à http://www.regular-expressions.info - un excellent tutoriel regex.

60
Tim Pietzcker