Quels caractères spéciaux doivent être échappés dans les expressions régulières?

389

Je suis fatigué de toujours essayer de deviner, si je dois échapper des caractères spéciaux comme ' ()[]{}|' etc. lors de l'utilisation de nombreuses implémentations de regexps.

C'est différent avec, par exemple, Python, sed, grep, awk, Perl, rename, Apache, find et ainsi de suite. Y a-t-il un ensemble de règles qui indique quand je devrais et quand je ne devrais pas, échapper des caractères spéciaux? Cela dépend-il du type d'expression régulière, comme PCRE, POSIX ou expressions régulières étendues?

Igor Katson
la source
4
Les bonnes bibliothèques d'expressions régulières ont des fonctions comme " escape()" pour permettre d'utiliser des chaînes arbitraires comme parties d'expressions régulières.
ivan_pozdeev
2
Vous pouvez utiliser des vérificateurs d'expression en ligne Regex comme gskinner.com/RegExr (c'est gratuit). (Tapez, puis passez la souris sur l'expression
régulière que
2
Échappez à tous les caractères non alphanumériques. période.
Salman von Abbas
2
Cette question a été ajoutée à la FAQ sur l'expression régulière de débordement de pile , sous «Autre».
aliteralmind
1
Cette question a été ajoutée à la FAQ sur l'expression régulière de débordement de pile , sous "Séquences d'échappement".
aliteralmind

Réponses:

365

Les personnages que vous devez et ceux que vous ne devez pas échapper dépendent en effet de la saveur regex avec laquelle vous travaillez.

Pour PCRE, et la plupart des autres versions dites compatibles avec Perl, échappez à ces classes de caractères externes:

.^$*+?()[{\|

et ces classes de caractères internes:

^-]\

Pour les expressions rationnelles étendues POSIX (ERE), échappez à ces classes de caractères externes (identiques à PCRE):

.^$*+?()[{\|

L'échappement de tout autre caractère est une erreur avec POSIX ERE.

Dans les classes de caractères, la barre oblique inverse est un caractère littéral dans les expressions régulières POSIX. Vous ne pouvez pas l'utiliser pour échapper à quoi que ce soit. Vous devez utiliser le "placement intelligent" si vous souhaitez inclure des métacaractères de classe de caractères en tant que littéraux. Mettez le ^ n'importe où sauf au début, le] au début et le - au début ou à la fin de la classe de caractères pour les faire correspondre littéralement, par exemple:

[]^-]

Dans les expressions régulières de base POSIX (BRE), ce sont des métacaractères que vous devez échapper pour supprimer leur signification:

.^$*[\

Les parenthèses et les accolades qui s'échappent dans les BRE leur donnent la signification particulière que leurs versions non échappées ont dans les ERE. Certaines implémentations (par exemple GNU) donnent également une signification spéciale à d'autres caractères lorsqu'elles sont échappées, comme \? et +. L'échappement d'un caractère autre que. ^ $ * () {} Est normalement une erreur avec les BRE.

À l'intérieur des classes de personnages, les BRE suivent la même règle que les ERE.

Si tout cela vous fait tourner la tête, prenez une copie de RegexBuddy . Sous l'onglet Créer, cliquez sur Insérer un jeton, puis sur Littéral. RegexBuddy ajoutera des échappements au besoin.

Jan Goyvaerts
la source
1
Il me semble que vous avez oublié le "/", qui doit également être échappé en dehors d'une classe.
jackthehipster
11
/n'est pas un métacaractère dans aucune des saveurs d'expression régulière que j'ai mentionnées, donc la syntaxe d'expression régulière ne nécessite pas de s'échapper. Lorsqu'une expression régulière est citée en tant que littéral dans un langage de programmation, les règles de formatage de chaîne ou d'expression régulière de ce langage peuvent nécessiter /ou "ou 'être échappées, et peuvent même exiger que `\` soit doublement échappé.
Jan Goyvaerts
2
Qu'en est-il du colon, ":"? Doit-il être échappé à l'intérieur des classes de personnages ainsi qu'à l'extérieur? en.wikipedia.org/wiki/Perl_Compatible_Regular_Expressions dit que "PCRE a des règles d'échappement cohérentes: tout caractère non alphanumérique peut être échappé pour signifier sa valeur littérale [...]"
nicolallias
4
PEUT être échappé n'est pas le même que DEVRAIT être échappé. La syntaxe PCRE n'exige jamais un deux-points littéral pour être échappé, donc échapper des deux-points littéraux ne fait que rendre votre expression rationnelle plus difficile à lire.
Jan Goyvaerts
1
Pour les ERE non POSIX (celui que j'utilise le plus souvent car c'est ce qui est implémenté par Tcl), échapper à d'autres choses ne génère pas d'erreurs.
slebetman
61

Saveurs RegEx modernes (PCRE)

Comprend C, C ++, Delphi, EditPad, Java, JavaScript, Perl, PHP (preg), PostgreSQL, PowerGREP, PowerShell, Python, REALbasic, Real Studio, Ruby, TCL, VB.Net, VBScript, wxWidgets, XML Schema, Xojo, XRegExp.
La compatibilité PCRE peut varier

    Nulle part: . ^ $ * + - ? ( ) [ ] { } \ |


Saveurs RegEx héritées (BRE / ERE)

Inclut awk, ed, egrep, emacs, GNUlib, grep, PHP (ereg), MySQL, Oracle, R, sed.
La prise en charge de PCRE peut être activée dans les versions ultérieures ou à l'aide d'extensions

ERE / awk / egrep / emacs

    En dehors d'une classe de personnages: . ^ $ * + ? ( ) [ { } \ |
    Dans une classe de personnages:^ - [ ]

BRE / ed / grep / sed

    À l'extérieur d'une classe de caractères: . ^ $ * [ \
    À l'intérieur d'une classe de caractères: ^ - [ ]
    Pour les littéraux, n'échappez pas: + ? ( ) { } |
    Pour un comportement d'expression régulière standard, échappez:\+ \? \( \) \{ \} \|


Remarques

  • En cas de doute sur un caractère spécifique, il peut être échappé comme \xFF
  • Les caractères alphanumériques ne peuvent pas être échappés avec une barre oblique inverse
  • Les symboles arbitraires peuvent être échappés avec une barre oblique inverse dans PCRE, mais pas BRE / ERE (ils ne doivent être échappés que lorsque cela est nécessaire). Pour PCRE, ] -il suffit de s'échapper dans une classe de caractères, mais je les ai conservés dans une seule liste pour plus de simplicité
  • Les chaînes d'expressions entre guillemets doivent également avoir les caractères de guillemets environnants échappés, et souvent avec des barres obliques inversées doublées (comme "(\")(/)(\\.)"par rapport /(")(\/)(\.)/à JavaScript)
  • Hormis les échappements, différentes implémentations d'expression régulière peuvent prendre en charge différents modificateurs, classes de caractères, ancres, quantificateurs et autres fonctionnalités. Pour plus de détails, consultez regular-expressions.info ou utilisez regex101.com pour tester vos expressions en direct
Beejor
la source
1
Il y a de nombreuses erreurs dans votre réponse, y compris mais sans s'y limiter: Aucune de vos saveurs "modernes" ne nécessite -ou ne ]doit être échappée en dehors des classes de caractères. POSIX (BRE / ERE) n'a pas de caractère d'échappement dans les classes de caractères. La saveur regex dans le RTL de Delphi est en fait basée sur PCRE. Python, Ruby et XML ont leurs propres versions qui sont plus proches de PCRE que des versions POSIX.
Jan Goyvaerts
1
@JanGoyvaerts Merci pour la correction. Les saveurs que vous avez mentionnées sont en effet plus proches de PCRE. Quant aux évasions, je les ai gardées de cette façon pour plus de simplicité; il est plus facile de se souvenir de s'échapper partout que de quelques exceptions. Les utilisateurs expérimentés sauront ce qui se passe s'ils veulent éviter quelques barres obliques inverses. Quoi qu'il en soit, j'ai mis à jour ma réponse avec quelques clarifications qui, espérons-le, répondent à certaines de ces questions.
Beejor
22

Malheureusement, il n'y a vraiment pas de jeu de codes d'échappement car il varie en fonction de la langue que vous utilisez.

Cependant, conserver une page comme la page des outils d'expression régulière ou cette feuille de triche d'expression régulière peut vous aider à filtrer rapidement les choses.

Dillie-O
la source
1
La feuille de triche Addedbytes est largement simplifiée et comporte des erreurs flagrantes. Par exemple, il dit \<et \>sont des limites de mots, ce qui est vrai uniquement (AFAIK) dans la bibliothèque d'expressions régulières Boost. Mais ailleurs, il dit <et >sont des métacaractères et doivent être échappés (vers \<et \>) pour les faire correspondre littéralement, ce qui n'est vrai dans aucune saveur
Alan Moore
5

Malheureusement, le sens de choses comme (et \ (sont échangés entre les expressions régulières de style Emacs et la plupart des autres styles. Donc, si vous essayez de les échapper, vous faites peut-être le contraire de ce que vous voulez.

Il faut donc vraiment savoir quel style vous essayez de citer.

Darron
la source
5

POSIX reconnaît plusieurs variantes des expressions régulières - les expressions régulières de base (BRE) et les expressions régulières étendues (ERE). Et même alors, il y a des bizarreries en raison des implémentations historiques des utilitaires standardisés par POSIX.

Il n'y a pas de règle simple pour savoir quand utiliser quelle notation, ou même quelle notation utilise une commande donnée.

Consultez le livre Mastering Regular Expressions de Jeff Friedl .

Jonathan Leffler
la source
4

Vraiment, il n'y en a pas. il existe environ un demi-zillion de syntaxes d'expression régulière différentes; ils semblent se résumer à Perl, EMACS / GNU et AT&T en général, mais je suis toujours aussi surpris.

Charlie Martin
la source
4

Parfois, un simple échappement n'est pas possible avec les personnages que vous avez répertoriés. Par exemple, l'utilisation d'une barre oblique inverse pour échapper à un crochet ne fonctionnera pas dans le côté gauche d'une chaîne de substitution dans sed, à savoir

sed -e 's/foo\(bar/something_else/'

J'ai tendance à utiliser une simple définition de classe de caractères à la place, donc l'expression ci-dessus devient

sed -e 's/foo[(]bar/something_else/'

que je trouve fonctionne pour la plupart des implémentations regexp.

Les classes de caractères BTW sont des composants regexp assez vanille, ils ont donc tendance à fonctionner dans la plupart des situations où vous avez besoin de caractères échappés dans les regexps.

Edit: Après le commentaire ci-dessous, je pensais simplement mentionner le fait que vous devez également prendre en compte la différence entre les automates à états finis et les automates à états non finis lorsque vous examinez le comportement de l'évaluation des expressions rationnelles.

Vous voudrez peut-être regarder "le livre de la balle brillante" aka Effective Perl ( lien Amazon purifié ), en particulier le chapitre sur les expressions régulières, pour avoir une idée de la différence dans les types d'évaluation du moteur d'expression rationnelle.

Tout le monde n'est pas un PCRE!

Quoi qu'il en soit, les expressions rationnelles sont si maladroites par rapport à SNOBOL ! Maintenant que était un cours de programmation intéressante! Avec celui de Simula .

Ah les joies d'étudier à l'UNSW à la fin des années 70! (-:

Rob Wells
la source
'sed' est une commande pour laquelle plain '(' n'est pas spécial mais '\ (' est spécial; en revanche, PCRE inverse le sens, donc '(' est spécial, mais '\ (' n'est pas. C'est exactement ce que le PO pose des questions.
Jonathan Leffler
sed est un utilitaire * nix qui utilise l'un des ensembles d'évaluation d'expression rationnelle les plus primitifs. PCRE n'entre pas dans la situation que je décris car elle implique une classe différente d'automates (in) finis avec la façon dont elle évalue les regexps. Je pense que ma suggestion pour l'ensemble minimum de syntaxe regexp tient toujours.
Rob Wells
1
Sur un système compatible POSIX, sed utilise POSIX BRE, que je couvre dans ma réponse. La version GNU sur le système Linux moderne utilise POSIX BRE avec quelques extensions.
Jan Goyvaerts
2

Pour PHP, "il est toujours sûr de faire précéder un caractère non alphanumérique par" \ "pour spécifier qu'il se représente." - http://php.net/manual/en/regexp.reference.escape.php .

Sauf si c'est un "ou '.: /

Pour échapper aux variables de modèle d'expression régulière (ou variables partielles) en PHP, utilisez preg_quote ()

zylstra
la source
2

Savoir quand et quoi échapper sans tentatives est nécessaire pour comprendre précisément la chaîne de contextes traversés par la chaîne. Vous spécifierez la chaîne du côté le plus éloigné à sa destination finale qui est la mémoire gérée par le code d'analyse regexp.

Soyez conscient de la façon dont la chaîne en mémoire est traitée: si peut être une chaîne simple à l'intérieur du code, ou une chaîne entrée dans la ligne de commande, mais a pourrait être soit une ligne de commande interactive soit une ligne de commande indiquée dans un fichier de script shell, ou à l'intérieur d'une variable en mémoire mentionnée par le code, ou un argument (chaîne) via une évaluation plus approfondie, ou une chaîne contenant du code généré dynamiquement avec n'importe quelle sorte d'encapsulation ...

Chacun de ce contexte a assigné des caractères avec des fonctionnalités spéciales.

Lorsque vous voulez passer le caractère littéralement sans utiliser sa fonction spéciale (locale au contexte), c'est le cas où vous devez l'échapper, pour le contexte suivant ... qui pourrait avoir besoin d'autres caractères d'échappement qui pourraient également avoir besoin d'être échappé dans le (s) contexte (s) précédent (s). De plus, il peut y avoir des choses comme le codage de caractères (le plus insidieux est utf-8 car il ressemble à ASCII pour les caractères communs, mais peut éventuellement être interprété même par le terminal en fonction de ses paramètres afin qu'il puisse se comporter différemment, puis l'attribut de codage de HTML / XML, il est nécessaire de bien comprendre le processus.

Par exemple, une expression rationnelle dans la ligne de commande commençant par perl -npe, doit être transférée à un ensemble d' appels système exec se connectant en tant que canal que le fichier gère, chacun de ces appels système exec a juste une liste d'arguments qui ont été séparés par des espaces (non échappés), et éventuellement des tuyaux (|) et redirection (> N> N> & M), parenthèses, expansion interactive de *et ?,$(())... (tout ceci sont des caractères spéciaux utilisés par le * sh qui peuvent sembler interférer avec le caractère de l'expression régulière dans le contexte suivant, mais ils sont évalués dans l'ordre: avant la ligne de commande. La ligne de commande est lue par un programme comme bash / sh / csh / tcsh / zsh, essentiellement à l'intérieur de guillemets doubles ou de guillemets simples, l'échappement est plus simple mais il n'est pas nécessaire de citer une chaîne dans la ligne de commande car la plupart du temps l'espace doit être préfixé avec une barre oblique inverse et la citation est il n'est pas nécessaire de laisser disponible la fonctionnalité de développement pour les caractères * et?, mais cette analyse est aussi différente du contexte que dans les guillemets. Ensuite, lorsque la ligne de commande est évaluée, l'expression rationnelle obtenue en mémoire (pas comme écrite dans la ligne de commande) reçoit le même traitement qu'elle serait dans un fichier source. Pour l'expression rationnelle, il y a un contexte de jeu de caractères entre crochets [],l'expression régulière perl peut être citée par un grand ensemble de caractères non alphanumériques (par exemple m // ou m: / better / for / path: ...).

Vous avez plus de détails sur les caractères dans d'autres réponses, qui sont très spécifiques au contexte d'expression rationnelle final. Comme je l'ai noté, vous mentionnez que vous trouvez l'échappement regexp avec des tentatives, c'est probablement parce que le contexte différent a un ensemble de caractères différent qui a confondu votre mémoire des tentatives (souvent la barre oblique inverse est le caractère utilisé dans ces différents contextes pour échapper à un caractère littéral au lieu de sa fonction ).

Marco Munari
la source
0

Pour Ionic (Typescript), vous devez doubler la barre oblique afin de scape les personnages. Par exemple (ceci correspond à certains caractères spéciaux):

"^(?=.*[\\]\\[!¡\'=ªº\\-\\_ç@#$%^&*(),;\\.?\":{}|<>\+\\/])"

Faites attention à ces ] [ - _ . /personnages. Ils doivent être doublés. Si vous ne le faites pas, vous allez avoir une erreur de type dans votre code.

Alejandro del Río
la source