Liste de tous les caractères spéciaux qui doivent être échappés dans une expression régulière

108

J'essaie de créer une application qui correspond à un modèle de message avec un message qu'un utilisateur tente d'envoyer. J'utilise Java regex pour faire correspondre le message. Le modèle / message peut contenir des caractères spéciaux.

Comment obtenir la liste complète des caractères spéciaux qui doivent être échappés pour que mon expression régulière fonctionne et corresponde dans le maximum de cas possibles?

Existe-t-il une solution universelle pour échapper tous les caractères spéciaux dans Java regex?

Avinash Nair
la source

Réponses:

94

Vous pouvez consulter le javadoc de la classe Pattern: http://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html

Vous devez échapper à tout caractère répertorié ici si vous voulez le caractère normal et non la signification spéciale.

Comme solution peut-être plus simple, vous pouvez placer le modèle entre \ Q et \ E - tout ce qui se trouve entre eux est considéré comme échappé.

Sorin
la source
43
Si vous trouvez \ Q et \ E difficiles à retenir, vous pouvez utiliser à la place Pattern.quote ("...")
mkdev
19
Je souhaite que vous les ayez réellement déclarés
Aleksandr Dubinsky
Pourquoi, @AleksandrDubinsky?
Sorin
55
@Sorin Parce que c'est l'esprit (non, la politique?) De Stack Exchange d'indiquer la réponse dans votre réponse plutôt que de simplement créer un lien vers une ressource hors site. De plus, cette page n'a pas non plus de liste claire. Une liste peut être trouvée ici: docs.oracle.com/javase/tutorial/essential/regex/literals.html , mais il indique "Dans certaines situations, les caractères spéciaux énumérés ci-dessus ne seront pas traités comme des métacaractères", sans expliquer ce qui va se passer si on essaie de leur échapper. Bref, cette question mérite une bonne réponse.
Aleksandr Dubinsky
8
"tout ce qui se trouve entre eux [ \Qet \E] est considéré comme échappé" - sauf les autres \Qet \Eles (qui peuvent potentiellement se produire dans le regex original). Il vaut donc mieux utiliser Pattern.quotecomme suggéré ici et ne pas réinventer la roue.
Sasha
92
  • Les caractères Java qui doivent être échappés dans les expressions régulières sont:
    \.[]{}()<>*+-=!?^$|
  • Deux des crochets de fermeture ( ]et }) ne doivent être échappés qu'après ouverture du même type de support.
  • Dans les []crochets, certains caractères (comme +et -) fonctionnent parfois sans échappement.
Tobi G.
la source
Existe-t-il un moyen de ne pas s'échapper mais d'autoriser ces personnages?
Dominika
1
Échapper un caractère signifie autoriser le caractère au lieu de l'interpréter comme un opérateur.
Tobi G.27
4
Un échappement à l' -intérieur []peut ne pas toujours fonctionner car il est utilisé pour définir des plages. Il est plus sûr d'y échapper. Par exemple, les motifs [-]et [-)]correspondent à la chaîne -mais pas avec [(-)].
Kenston Choi
1
Même si la réponse acceptée répond à la question, cette réponse m'a été plus utile lorsque je cherchais simplement une liste rapide.
Old Nick
-=!n'ont pas nécessairement besoin d'être échappés, cela dépend du contexte. Par exemple, comme une seule lettre, ils fonctionnent comme une expression régulière constante.
Hawk
29

Pour échapper, vous pouvez simplement utiliser ceci à partir de Java 1.5 :

Pattern.quote("$test");

Vous correspondrez exactement au mot $test

madx
la source
Pourquoi n'est-ce pas la réponse la plus appréciée? Cela résout le problème sans entrer dans les détails complexes de la liste de tous les caractères à échapper et cela fait partie du JDK - pas besoin d'écrire de code supplémentaire! Facile!
Volksman
17

Selon la page de documentation des littéraux de chaîne / métacaractères , ils sont:

<([{\^-=$!|]})?*+.>

De plus, ce serait cool d'avoir cette liste référencée quelque part dans le code, mais je ne sais pas où cela pourrait être ...

Bohdan
la source
11
String escaped = tnk.replaceAll("[\\<\\(\\[\\{\\\\\\^\\-\\=\\$\\!\\|\\]\\}\\)\\?\\*\\+\\.\\>]", "\\\\$0");
marbel82
1
Le modèle javadoc dit que c'est une erreur d'utiliser une barre oblique inverse avant tout caractère alphabétique qui ne désigne pas une construction échappée, mais une barre oblique inverse peut être utilisée avant un caractère non alphabétique, que ce caractère fasse partie ou non d'une construction sans échappement. Par conséquent, une regex beaucoup plus simple suffira: s.replaceAll("[\\W]", "\\\\$0")\Wdésigne des caractères non mot.
Joe Bowbeer
6

En combinant ce que tout le monde a dit, je propose ce qui suit, de garder la liste des caractères spéciaux à RegExp clairement listés dans leur propre chaîne, et d'éviter d'avoir à essayer d'analyser visuellement des milliers de "\\". Cela semble fonctionner assez bien pour moi:

final String regExSpecialChars = "<([{\\^-=$!|]})?*+.>";
final String regExSpecialCharsRE = regExSpecialChars.replaceAll( ".", "\\\\$0");
final Pattern reCharsREP = Pattern.compile( "[" + regExSpecialCharsRE + "]");

String quoteRegExSpecialChars( String s)
{
    Matcher m = reCharsREP.matcher( s);
    return m.replaceAll( "\\\\$0");
}
NeuroDuck
la source
5

Sur la suggestion de @ Sorin concernant les documents Java Pattern, il semble que les caractères à échapper soient au moins:

\.[{(*+?^$|
Pete
la source
4
String escaped = regexString.replaceAll("([\\\\\\.\\[\\{\\(\\*\\+\\?\\^\\$\\|])", "\\\\$1");
fracz
2
)doit également être échappé, et selon que vous êtes à l'intérieur ou à l'extérieur d'une classe de caractères, il peut y avoir plus de caractères à échapper, auquel cas Pattern.quotefait un assez bon travail pour échapper une chaîne à utiliser à la fois à l'intérieur et à l'extérieur de la classe de caractères.
nhahtdh
3

Le Pattern.quote(String s)genre de fait ce que vous voulez. Cependant il laisse un peu à désirer; il n'échappe pas réellement les caractères individuels, il enveloppe simplement la chaîne avec \Q...\E.

Il n'y a pas de méthode qui fait exactement ce que vous recherchez, mais la bonne nouvelle est qu'il est en fait assez simple d'échapper à tous les caractères spéciaux d'une expression régulière Java:

regex.replaceAll("[\\W]", "\\\\$0")

Pourquoi ça marche? Eh bien, la documentation pour Patterndit spécifiquement qu'il est permis d'échapper aux caractères non alphabétiques qui ne doivent pas nécessairement être échappés:

C'est une erreur d'utiliser une barre oblique inverse avant tout caractère alphabétique qui ne désigne pas une construction échappée; ceux-ci sont réservés pour les futures extensions du langage d'expression régulière. Une barre oblique inverse peut être utilisée avant un caractère non alphabétique, que ce caractère fasse partie ou non d'une construction sans échappement.

Par exemple, ;n'est pas un caractère spécial dans une expression régulière. Cependant, si vous y échappez, Patternsera toujours interprété \;comme ;. Voici quelques exemples supplémentaires:

  • >devient \>ce qui équivaut à>
  • [devient \[qui est la forme échappée de[
  • 8est toujours 8.
  • \)devient \\\)qui est les formes échappées \et (concaténées.

Remarque: La clé est la définition de «non alphabétique», qui dans la documentation signifie en réalité des caractères «non- mots », ou des caractères en dehors du jeu de caractères [a-zA-Z_0-9].

rouleur
la source
2

de l'autre côté de la pièce, vous devez utiliser l'expression régulière "non-char" qui ressemble à ceci si les caractères spéciaux = allChars - nombre - ABC - espace dans le contexte de votre application.

String regepx = "[^\\s\\w]*";
Bo6Bear
la source
2

bien que la réponse soit pour Java, mais le code peut être facilement adapté à partir de cette extension de chaîne Kotlin que j'ai créée (adaptée de ce @brcolow fourni):

private val escapeChars = charArrayOf(
    '<',
    '(',
    '[',
    '{',
    '\\',
    '^',
    '-',
    '=',
    '$',
    '!',
    '|',
    ']',
    '}',
    ')',
    '?',
    '*',
    '+',
    '.',
    '>'
)

fun String.escapePattern(): String {
    return this.fold("") {
      acc, chr ->
        acc + if (escapeChars.contains(chr)) "\\$chr" else "$chr"
    }
}

fun main() {
    println("(.*)".escapePattern())
}

impressions \(\.\*\)

vérifiez-le en action ici https://pl.kotl.in/h-3mXZkNE

pocésar
la source
1

En supposant que vous avez et que vous faites confiance (pour faire autorité) la liste des caractères d'échappement que Java regex utilise (ce serait bien si ces caractères étaient exposés dans un membre de la classe Pattern), vous pouvez utiliser la méthode suivante pour échapper le caractère si cela est effectivement nécessaire:

private static final char[] escapeChars = { '<', '(', '[', '{', '\\', '^', '-', '=', '$', '!', '|', ']', '}', ')', '?', '*', '+', '.', '>' };

private static String regexEscape(char character) {
    for (char escapeChar : escapeChars) {
        if (character == escapeChar) {
            return "\\" + character;
        }
    }
    return String.valueOf(character);
}
brcolow
la source