Guide pour échapper des caractères dans Java RegExps

1. Vue d'ensemble

L'API d'expressions régulières en Java, java.util.regex est largement utilisée pour la correspondance de modèles. Pour en savoir plus, vous pouvez suivre cet article.

Dans cet article, nous allons nous concentrer sur les caractères d'échappement avec une expression régulière et montrer comment cela peut être fait en Java.

2. Caractères RegExp spéciaux

Selon la documentation de l'API des expressions régulières Java, il existe un ensemble de caractères spéciaux également appelés métacaractères présents dans une expression régulière.

Lorsque nous voulons autoriser les personnages tels quels au lieu de les interpréter avec leurs significations spéciales, nous devons leur échapper. En échappant ces caractères, nous les forçons à être traités comme des caractères ordinaires lors de la mise en correspondance d'une chaîne avec une expression régulière donnée.

Les métacaractères dont nous avons généralement besoin pour échapper de cette manière sont:

Regardons un exemple de code simple où nous faisons correspondre une chaîne d' entrée avec un modèle exprimé dans une expression régulière.

Ce test montre que pour une chaîne d'entrée donnée foof lorsque le motif foo . ( toto se terminant par un point) est mis en correspondance, il renvoie une valeur true qui indique que la correspondance est réussie.

@Test public void givenRegexWithDot_whenMatchingStr_thenMatches() { String strInput = "foof"; String strRegex = "foo."; assertEquals(true, strInput.matches(strRegex)); }

Vous vous demandez peut-être pourquoi la correspondance réussit quand il n'y a pas de caractère point (.) Présent dans la chaîne d' entrée ?

La réponse est simple. Le point (.) Est un métacaractère - la signification particulière du point ici est qu'il peut y avoir «n'importe quel caractère» à sa place. Par conséquent, il est clair comment le matcher a déterminé qu'une correspondance est trouvée.

Disons que nous ne voulons pas traiter le caractère point (.) Avec sa signification unique. Au lieu de cela, nous voulons qu'il soit interprété comme un signe de point. Cela signifie que dans l'exemple précédent, nous ne voulons pas laisser le motif foo. pour avoir une correspondance dans la chaîne d' entrée .

Comment gérerions-nous une telle situation? La réponse est: nous devons échapper le caractère point (.) Afin que sa signification particulière soit ignorée.

Explorons-le plus en détail dans la section suivante.

3. Caractères d'échappement

Selon la documentation de l'API Java pour les expressions régulières, il existe deux façons d'échapper des caractères qui ont une signification particulière. En d'autres termes, pour les forcer à être traités comme des caractères ordinaires.

Voyons ce qu'ils sont:

  1. Faites précéder un métacaractère d'une barre oblique inverse (\)
  2. Entourez un méta-caractère avec \ Q et \ E

Cela signifie simplement que dans l'exemple que nous avons vu précédemment, si nous voulons échapper le caractère point, nous devons mettre un caractère barre oblique inverse avant le caractère point. Alternativement, nous pouvons placer le caractère point entre \ Q et \ E.

3.1. Échapper à l'aide de la barre oblique inverse

C'est l'une des techniques que nous pouvons utiliser pour échapper les métacaractères dans une expression régulière. Cependant, nous savons que la barre oblique inverse est également un caractère d'échappement dans les littéraux Java String . Par conséquent, nous devons doubler la barre oblique inverse lorsque vous l'utilisez pour précéder n'importe quel caractère (y compris le caractère \ lui-même).

Par conséquent, dans notre exemple, nous devons changer l'expression régulière comme indiqué dans ce test:

@Test public void givenRegexWithDotEsc_whenMatchingStr_thenNotMatching() { String strInput = "foof"; String strRegex = "foo\\."; assertEquals(false, strInput.matches(strRegex)); }

Ici, le caractère point est échappé, donc le matcher le traite simplement comme un point et essaie de trouver un motif qui se termine par le point (c'est-à-dire foo ).

Dans ce cas, il renvoie false car il n'y a pas de correspondance dans la chaîne d' entrée pour ce modèle.

3.2. Échapper à l'aide de \ Q & \ E

Alternativement, nous pouvons utiliser \ Q et \ E pour échapper au caractère spécial. \ Q indique que tous les caractères jusqu'au \ E doit être échappé et \ E signifie que nous devons mettre fin à l'échappement qui a été commencé avec \ Q .

Cela signifie simplement que tout ce qui se trouve entre \ Q et \ E serait échappé.

Dans le test présenté ici, le split () de la classe String fait une correspondance en utilisant l'expression régulière qui lui est fournie.

Notre exigence est de diviser la chaîne d'entrée par le caractère pipe (|) en mots. Par conséquent, nous utilisons un modèle d'expression régulière pour ce faire.

Le caractère pipe est un métacaractère qui doit être échappé dans l'expression régulière.

Ici, l'échappement se fait en plaçant le caractère pipe entre \ Q et \ E :

@Test public void givenRegexWithPipeEscaped_whenSplitStr_thenSplits() \\E"; assertEquals(4, strInput.split(strRegex).length); 

4. La méthode Pattern.quote (String S)

La méthode Pattern.Quote (String S) de la classe java.util.regex.Pattern convertit un modèle d'expression régulière donné String en un modèle littéral String. Cela signifie que tous les métacaractères de la chaîne d' entrée sont traités comme des caractères ordinaires.

Utiliser cette méthode serait une alternative plus pratique que d'utiliser \ Q & \ E car elle enveloppe la chaîne donnée avec eux.

Voyons cette méthode en action:

@Test public void givenRegexWithPipeEscQuoteMeth_whenSplitStr_thenSplits() bar

In this quick test, the Pattern.quote() method is used to escape the given regex pattern and transform it into a String literal. In other words, it escapes all the metacharacters present in the regex pattern for us. It is doing a similar job to \Q & \E.

The pipe character is escaped by the Pattern.quote() method and the split() interprets it as a String literal by which it divides the input.

As we can see, this is a much cleaner approach and also the developers do not have to remember all the escape sequences.

We should note that Pattern.quote encloses the whole block with a single escape sequence. If we wanted to escape characters individually, we would need to use a token replacement algorithm.

5. Additional Examples

Let's look at how the replaceAll() method of java.util.regex.Matcher works.

If we need to replace all occurrences of a given character String with another, we can use this method by passing a regular expression to it.

Imagine we have an input with multiple occurrences of the $ character. The result we want to get is the same string with the $ character replaced by £.

Ce test montre comment le modèle $ est passé sans être échappé:

@Test public void givenRegexWithDollar_whenReplacing_thenNotReplace() { String strInput = "I gave $50 to my brother." + "He bought candy for $35. Now he has $15 left."; String strRegex = "$"; String strReplacement = "£"; String output = "I gave £50 to my brother." + "He bought candy for £35. Now he has £15 left."; Pattern p = Pattern.compile(strRegex); Matcher m = p.matcher(strInput); assertThat(output, not(equalTo(m.replaceAll(strReplacement)))); }

Le test affirme que $ n'est pas correctement remplacé par £ .

Maintenant, si nous échappons au modèle regex, le remplacement se produit correctement et le test passe comme indiqué dans cet extrait de code:

@Test public void givenRegexWithDollarEsc_whenReplacing_thenReplace() { String strInput = "I gave $50 to my brother." + "He bought candy for $35. Now he has $15 left."; String strRegex = "\\$"; String strReplacement = "£"; String output = "I gave £50 to my brother." + "He bought candy for £35. Now he has £15 left."; Pattern p = Pattern.compile(strRegex); Matcher m = p.matcher(strInput); assertEquals(output,m.replaceAll(strReplacement)); }

Notez le \\ $ ici, qui fait l'affaire en échappant le caractère $ et en faisant correspondre le modèle avec succès.

6. Conclusion

Dans cet article, nous avons examiné les caractères d'échappement dans les expressions régulières en Java.

Nous avons discuté de la raison pour laquelle les expressions régulières doivent être échappées et des différentes manières dont cela peut être réalisé.

Comme toujours, le code source lié à cet article se trouve à l'adresse over sur GitHub.