GNU/Linux >> Tutoriels Linux >  >> Linux

Pourquoi l'expression régulière fonctionne-t-elle dans X mais pas dans Y ?

J'ai écrit une expression régulière qui fonctionne bien dans un certain programme (grep, sed, awk, perl, python, ruby, ksh, bash, zsh, find, emacs, vi, vim, gedit, …). Mais lorsque je l'utilise dans un programme différent (ou sur une variante Unix différente), il cesse de correspondre. Pourquoi ?

Réponse acceptée :

Malheureusement, pour des raisons historiques, différents outils ont une syntaxe d'expression régulière légèrement différente, et parfois certaines implémentations ont des extensions qui ne sont pas prises en charge par d'autres outils. Bien qu'il existe un terrain d'entente, il semble que chaque créateur d'outils ait fait des choix différents.

La conséquence est que si vous avez une expression régulière qui fonctionne dans un outil, vous devrez peut-être la modifier pour qu'elle fonctionne dans un autre outil. Les principales différences entre les outils courants sont :

  • si les opérateurs +?|(){} exiger une barre oblique inverse ;
  • quelles extensions sont prises en charge au-delà des bases .[]*^$ et généralement +?|()

Dans cette réponse, je liste les principales normes. Consultez la documentation des outils que vous utilisez pour plus de détails.

La comparaison de Wikipédia des moteurs d'expressions régulières contient un tableau répertoriant les fonctionnalités prises en charge par les implémentations courantes.

Expressions régulières de base (BRE)

Les expressions régulières de base sont codifiées par le standard POSIX. C'est la syntaxe utilisée par grep , sed et vi . Cette syntaxe offre les fonctionnalités suivantes :

  • ^ et $ correspond uniquement au début et à la fin d'une ligne.
  • . correspond à n'importe quel caractère (ou n'importe quel caractère sauf une nouvelle ligne).
  • […] correspond à n'importe quel caractère indiqué entre parenthèses (jeu de caractères). Si le premier caractère après la parenthèse ouvrante est un ^ , les caractères qui ne sont pas répertoriés sont mis en correspondance à la place. Pour inclure un ] , placez-le immédiatement après l'ouverture [ (ou après [^ s'il s'agit d'un ensemble négatif). Si - est entre deux caractères, il dénote une plage ; pour inclure un - littéral , placez-le là où il ne peut pas être analysé en tant que plage.
  • Barre oblique inverse avant l'un des ^$.*[ cite le caractère suivant.
  • * correspond au caractère ou à la sous-expression qui précède 0, 1 ou plusieurs fois.
  • (…) est un groupe syntaxique, à utiliser avec le * opérateur ou backreferences et DIGIT remplacements.
  • Références 1 , 2 , … correspondent au texte exact correspondant au groupe correspondant, par ex. (fo*)(ba*)1 correspond à foobaafoo mais pas foobaafo . Il n'y a pas de moyen standard de se référer au 10ème groupe et au-delà (la signification standard de 10 est le premier groupe suivi d'un ).

Les fonctionnalités suivantes sont également standard, mais absentes de certaines implémentations restreintes :

  • {m,n} correspond au caractère ou à la sous-expression précédente entre m à n fois; n ou m peut être omis, et {m} signifie exactement m .
  • À l'intérieur des crochets, des classes de caractères peuvent être utilisées, par exemple [[:alpha:]] correspond à n'importe quelle lettre. Les implémentations modernes des expressions entre parenthèses) incluent également des éléments de classement comme [.ll.] et des classes d'équivalence comme [=a=] .

Les extensions suivantes sont courantes (en particulier dans les outils GNU), mais elles ne se trouvent pas dans toutes les implémentations. Consultez le manuel de l'outil que vous utilisez.

  • | pour l'alternance :foo|bar correspond à foo ou bar .
  • ? (abréviation de {0,1} ) et + (abréviation de {1,} ) correspondent au caractère ou à la sous-expression qui précède au plus 1 fois, ou au moins 1 fois respectivement.
  • n correspond à une nouvelle ligne, t correspond à un onglet, etc.
  • w correspond à n'importe quel mot constitutif (abréviation de [_[:alnum:]] mais avec des variations en termes de localisation) et W correspond à tout caractère qui n'est pas un constituant de mot.
  • < et > faire correspondre la chaîne vide uniquement au début ou à la fin d'un mot respectivement ; b correspond à l'un ou l'autre, et B correspond à où b pas.

Notez que les outils sans le | L'opérateur n'a pas toute la puissance des expressions régulières. Les références arrière permettent quelques choses supplémentaires qui ne peuvent pas être faites avec des expressions régulières au sens mathématique.

Expressions régulières étendues (ERE)

Les expressions régulières étendues sont codifiées par le standard POSIX. Leur avantage majeur par rapport à BRE est la régularité :tous les opérateurs standards sont des caractères de ponctuation nus, une barre oblique inverse devant un caractère de ponctuation le cite toujours. C'est la syntaxe utilisée par awk , grep -E ou egrep , GNU sed -r , et le =~ de bash opérateur. Cette syntaxe offre les fonctionnalités suivantes :

  • ^ et $ correspond uniquement au début et à la fin d'une ligne.
  • . correspond à n'importe quel caractère (ou n'importe quel caractère sauf une nouvelle ligne).
  • […] correspond à n'importe quel caractère indiqué entre parenthèses (jeu de caractères). Complémentation avec un ^ initial et les gammes fonctionnent comme dans BRE (voir ci-dessus). Les classes de caractères peuvent être utilisées mais sont absentes de quelques implémentations. Les implémentations modernes prennent également en charge les classes d'équivalence et les éléments de classement. Une barre oblique inverse entre parenthèses cite le caractère suivant dans certaines implémentations mais pas toutes ; utilisez \ signifie une barre oblique inverse pour la portabilité.
  • (…) est un groupe syntaxique, à utiliser avec * ou DIGIT remplacements.
  • | pour l'alternance :foo|bar correspond à foo ou bar .
  • * , + et ? correspond au caractère ou à la sous-expression qui précède un certain nombre de fois :0 ou plus pour * , 1 ou plus pour + , 0 ou 1 pour ? .
  • La barre oblique inverse cite le caractère suivant s'il n'est pas alphanumérique.
  • {m,n} correspond au caractère ou à la sous-expression précédente entre m et n fois (absent de certaines implémentations); n ou m peut être omis, et {m} signifie exactement m .
  • Quelques extensions courantes comme dans BRE :DIGIT backreferences (notamment absentes dans awk sauf dans l'implémentation de busybox où vous pouvez utiliser $0 ~ "(...)\1" ); caractères spéciaux n , t , etc.; limites de mots b et B , constituants du mot b et B , …
Connexes :Ma théorie précédente était fausse, alors pourquoi cela fonctionne-t-il ?

PCRE (expressions régulières compatibles Perl)

PCRE sont des extensions d'ERE, introduites à l'origine par Perl et adoptées par GNU grep -P et de nombreux outils et langages de programmation modernes , généralement via la bibliothèque PCRE. Voir la documentation Perl pour une mise en forme agréable avec des exemples. Toutes les fonctionnalités de la dernière version de Perl ne sont pas prises en charge par PCRE (par exemple, l'exécution de code Perl n'est prise en charge qu'en Perl). Voir le manuel PCRE pour un résumé des fonctionnalités prises en charge. Les principaux ajouts à ERE sont :

  • (?:…) est un groupe non capturant :comme (…) , mais ne compte pas pour les références arrière.
  • (?=FOO)BAR (anticipation) correspond à BAR , mais seulement s'il existe également une correspondance pour FOO commençant à la même position. Ceci est très utile pour ancrer une correspondance sans inclure le texte suivant dans la correspondance :foo(?=bar) correspond à foo mais seulement s'il est suivi de bar .
  • (?!FOO)BAR (anticipation négative) correspond à BAR , mais il n'y a pas non plus de correspondance pour FOO au même poste. Par exemple (?!foo)[a-z]+ correspond à tout mot en minuscule qui ne commence pas par foo; [a-z]+(?![0-9) correspond à tout mot en minuscule qui n'est pas suivi d'un chiffre (donc dans foo123 , il correspond à fo mais pas foo ).
  • (?<=FOO)BAR (lookbehind) correspond à BAR , mais seulement s'il est immédiatement précédé d'une correspondance pour FOO . FOO doit avoir une longueur connue (vous ne pouvez pas utiliser d'opérateurs de répétition tels que * ). Ceci est très utile pour ancrer une correspondance sans inclure le texte précédent dans la correspondance :(?<=^| )foo correspond à foo mais seulement s'il est précédé d'un espace ou du début de la chaîne.
  • (?<!FOO)BAR (lookbehind négatif) correspond à BAR , mais seulement s'il n'est pas immédiatement précédé d'une correspondance pour FOO . FOO doit avoir une longueur connue (vous ne pouvez pas utiliser d'opérateurs de répétition tels que * ). Ceci est très utile pour ancrer une correspondance sans inclure le texte précédent dans la correspondance :(?<![a-z])foo correspond à foo mais seulement s'il n'est pas précédé d'une lettre minuscule.

Emacs

La syntaxe d'Emacs est intermédiaire entre BRE et ERE. En plus d'Emacs, c'est la syntaxe par défaut pour -regex dans GNU trouver. Emacs propose les opérateurs suivants :

  • ^ , $ , . , […] , * , + , ? comme dans ERE
  • (…) , | , {…} , DIGIT comme dans BRE
  • plus de séquences de lettres avec barre oblique inversée ; < et > pour les limites de mots ; et plus encore dans les versions récentes d'Emacs, qui ne sont souvent pas prises en charge par d'autres moteurs avec une syntaxe de type Emacs.
Connexe :Utilisez la recherche pour trouver un certain répertoire et supprimer tous les fichiers qu'il contient, sauf un répertoire ?

globules Shell

Les shell globs (wildcards) effectuent une correspondance de modèle avec une syntaxe complètement différente des expressions régulières et moins puissante. En plus des shells, ces jokers sont disponibles avec d'autres outils tels que find -name et les filtres rsync. Les modèles POSIX incluent les fonctionnalités suivantes :

  • ? correspond à n'importe quel caractère unique.
  • […] est un jeu de caractères comme dans les syntaxes d'expressions régulières courantes. Certains shells ne prennent pas en charge les classes de caractères. Certains shells nécessitent ! au lieu de ^ pour nier l'ensemble.
  • * correspond à n'importe quelle séquence de caractères (souvent sauf / lors de la correspondance des chemins de fichiers ; si / est exclu de * , puis ** inclut parfois / , mais consultez la documentation de l'outil).
  • La barre oblique inverse cite le caractère suivant.

Ksh offre des fonctionnalités supplémentaires qui donnent à son pattern matching toute la puissance des expressions régulières. Ces fonctionnalités sont également disponibles dans bash après avoir exécuté shopt -s extglob . Zsh a une syntaxe différente mais peut également prendre en charge la syntaxe de ksh après setopt ksh_glob .


Linux
  1. Pourquoi le fichier de traduction Bash ne contient-il pas tous les textes d'erreur ?

  2. Linux - Pourquoi Setuid ne fonctionne-t-il pas ??

  3. Linux – Pourquoi la locale Es_mx fonctionne-t-elle mais pas Es ?

  4. La définition d'une expression régulière ?

  5. Pourquoi ce "pendant la lecture" fonctionne-t-il dans un terminal, mais pas dans un script shell ?

Pourquoi "zip" dans une boucle For fonctionne-t-il lorsque le fichier existe, mais pas lorsqu'il n'existe pas ?

Pourquoi le parent Shell Here-document ne fonctionne pas pour la sous-commande dans Dash mais Bash fonctionne?

Pourquoi Tomcat fonctionne-t-il avec le port 8080 mais pas 80 ?

wc -l ne compte PAS le dernier du fichier s'il n'a pas de caractère de fin de ligne

La répétition automatique ne fonctionne pas

Pourquoi le bit setuid fonctionne-t-il de manière incohérente ?