14.5. Syntaxe d'Expressions Rationnelles

Les expressions rationnelles ont une syntaxe dans laquelle quelques caractères ont une signification particulière, et les autres sont ordinaires. Un caractère ordinaire est une expression rationnelle à laquelle correspond ce même caractère, et rien d'autre. Les caractères spéciaux sont $, ^, ., *, +, ?, [, ] et \. Tout autre caractère apparaissant dans l'expression rationnelle est ordinaire, à moins qu'un \ le précède.

Par exemple, f n'est pas un caractère spécial, c'est donc un caractère ordinaire, et f est donc une expression rationnelle qui correspond à la chaîne f et à aucune autre chaîne. (Elle ne correspond pas à la chaîne ff.) De même, o est une expression rationnelle qui correspond seulement à o. (Lorsque la distinction de casse est ignorée, ces regexps correspondent aussi à F et O, mais nous considérons ceci comme une généralisation de "la même chaîne", plutôt qu'une exception.)

Deux expressions rationnelles quelconques a et b peuvent être concaténées. Le résultat est une expression rationnelle qui correspond à une chaîne si a correspond à une partie du début de cette chaîne et b correspond au reste de cette chaîne.

Comme exemple simple, nous pouvons concaténer les expressions rationnelles f et o pour obtenir l'expression rationnelle fo, qui correspond uniquement à la chaîne fo. Trivial. Pour faire quelque chose de non trivial, vous avez besoin d'utiliser un des caractères spéciaux. En voici une liste.

. (Point)

est un caractère spécial auquel correspond tout caractère excepté newline. En utilisant la concaténation, vous pouvez créer des expressions rationnelles comme a.b, qui correspond à toute chaîne de trois caractères commençant par a et finissant par b.

*

n'est pas une construction par elle-même ; c'est un opérateur suffixe qui indique de faire correspondre l'expression rationnelle précédente répétitivement autant de fois que possible. Ainsi, o* correspond à un quelconque nombre de o (aucun o inclus).

* s'applique toujours à l'expression précéednte la plus petite possible. Ainsi, fo* a un o répétitif, et non un fo répétitif. Elle correspond à f, fo, foo, etc.

La recherche de correspondance d'une construction * fait correspondre, immédiatement, autant de répétitions pouvant être trouvées. Elle continue alors avec la suite du motif. Si la suite échoue, un retour en arrière est utilisé, supprimant certaines des correspondances de la construction * modifiée, au cas où il serait possible de faire correspondre la suite du motif. Par exemple, en faisant correspondre ca*ar sur la chaîne caaar, le a* essaie d'abord de correspondre aux trois a ; mais la suite du motif est ar et il ne reste plus que r à faire correspondre ; cet essai échoue alors. La prochaine alternative est que a* corresponde à deux a exactement. Avec ce choix, la suite de la regexp correspond parfaitement.

+

est un opérateur suffixe, similaire à * excepté qu'il doit faire correspondre l'expression précédente au moins une fois. Ainsi, par exemple, ca+r correspond aux chaînes car et caaaar mais non à la chaîne cr, alors que ca*r correspond à ces trois chaînes.

?

est un opérateur suffixe, similaire à * excepté qu'il fait correspondre l'expression précédente soit une fois, soit pas du tout. Par exemple, ca?r correspond à car ou cr ; rien d'autre.

*?, +?, ??

sont les variantes non gourmandes des opérateurs précédents. Les opérateurs normaux *, +, ? sont gourmands dans le fait qu'ils correspondent à des chaînes aussi longues que possible, aussi longtemps que la regexp entière peut continuer à correspondre. Avec un ? à la suite, elles sont non gourmandes ; elles vont correspondre à des chaînes aussi courtes que possible.

Ainsi, ab* et ab*? peuvent toutes deux correspondre à la chaîne a et à la chaîne abbbb ; mais si vous essayez de faire correspondre les deux avec le texte abbb, ab* va correspondre à la chaîne entière (la correspondance valide la plus longue possible), alors que ab*? va correspondre à a seulement (la correspondance la plus courte possible).

\{n\}

est un opérateur suffixe qui spécifie une répétition n fois--ansi, l'expression rationnelle précédente dot correspondre exactement n fois à la suite. Par exemple, x\{4\} correspond à la chaîne xxxx et rien d'autre.

\{n,m\}

est un opérateur suffixe qui spécifie une répétition entre n et m fois--ainsi, l'expression rationnelle précédente doit correspondre au moins n fois, mais pas plus de m fois. Si m est omis, il n'y a alors pas de limite supérieure, mais l'expression rationnelle précédente doit correspondre au moins n fois. \{0,1\} est équivalent à ?. \{0,\} est équivalent à *. \{1,\} est équivalent à +.

[ … ]

est un jeu de caractères, qui commence avec [ et termine par ]. Dans sa forme la plus simple, les caractères entre les deux crochets sont ce à quoi ce jeu peut correspondre.

Ainsi, [ad] correspond soit à un a soit à un d, et [ad]* correspond à une chaîne composée uniquement de a et de d (incluant la chaîne vide), de quoi il découle que c[ad]*r correspond à cr, car, cdr, caddaar, etc.

Vous pouvez aussi inclure un rang de caractères dans un jeu de caractères, en écrivant les caractères de début et de fin séparés par un -. Ainsi, [a-z] correspond à n'importe quelle lettre ASCII minuscule. Des rangs peuvent être mélangés librement avec des caractères individuels, comme dans [a-z$%.], qui correspond à n'importe quelle lettre ASCII minuscule ou $, % un point.

Notez que les caractères habituellement spéciaux pour une regexp ne le sont pas dans un jeu de caractères. Un jeu complètement différent de caractères spéciaux existe dans les jeux de caractères : ], - et ^.

Pour inclure un ] dans un jeu de caractères, il doit être le premier des caractères. Par exemple, []a] correspond à ] ou a. Pour inclure -, placez - comme premier ou dernier caractère du jeu, ou placez-le après un raaang. Ainsi, []-] correspond à ] et -.

Pour inclure ^ dans un jeu, placez-le n'importe où sauf au début du jeu.

Lorsque vous utilisez un rang dans une recherche non sensible à la casse, vous devez écrire les deux extrémités du rang en majuscule, ou les deux en minuscule, ou les deux doivent ne pas être des lettres. Le comportement d'un rang avec des casses mixées comme A-z est mal défini, et pourra être modifié dans des versions futures d'Emacs.

[^ … ]

[^ commence un jeu de caractères complémentaire, qui correspond à tout caractère non spécifié dans le jeu. Ainsi, [^a-z0-9A-Z] correspond à tous les caractères sauf aux lettres et aux chiffres.

^ n'est pas un caractère spécial dans un jeu de caractères à moins qu'il ne soit le premier caractère. Le caractère suivant le ^ est traité comme étant premier (en d'autres mots, - et ] ne sont pas spéciaux s'ils suivent ^).

Un jeu de caractères complémentaire peut correspondre à un newline, sauf si newline est mentionné dans les caractères auxquels ne pas correspondre. C'est en contraste avec les regexps de programmes tels que grep.

^

est un caractère spécial qui correspond à la chaîne vide, mais seulement en début d'une ligne dans le texte à faire correspondre. Autrement, il ne correspond à rien. Ainsi, ^foo correspond à foo placé en début de ligne.

$

est similaire à ^ mais correpond seulement en fin de ligne. Ainsi, x+$ correspond à une chaîne d'un x ou plus en fin de ligne.

\

a deux fonctions : il cite les caractères spéciaux (\ inclus), et introduit des constructions spéciales supplémentaires.

Puisque \ cite les caractères spéciaux, \$ est une expression rationnelle qui correspond seulement à $, et \[ est une expression rationnelle qui correspond seulement à [, et ainsi de suite.

Note : pour une compatibilité historique, les caractères spéciaux sont traités comme ordinaires s'ils sont dans un contexte où leur "caractère" spécial n'a pas de sens. Par exemple, *foo traite * comme ordinaire car il n'y a pas d'expression précédente sur laquelle * puisse agir. C'est une pratique pauvre que de dépendre de ce comportement ; il est préférable de toujours citer les caractères spéciaux, indépendamment de l'endroit où ils apparaissent.

Pour la plus grande part, \ suivi d'un caractère correspond seulement à ce caractère. Il y a toutefois quelques exceptions : des séquences de deux caractères commençant par \ qui une signification particulière. Le second caractère de la séquence est toujours un caractère ordinaire lorsqu'il est utilisé seul. Voici un tableau des constructions \.

\|

spécifie une alternative. Deux expressions rationnelles a et b séparées par \| forment une expression qui correspond à un texte si a correspond à ce texte ou si b y correspond. il fonctionne en essayant de faire correspondre a, et en cas d'échec, essaie de faire correspondre b.

Ainsi, foo\|bar correspond soit à foo soit à bar, et rien d'autre.

\| s'applique aux expressions qui l'entoure les plus longues possibles. Seul un regroupement \( … \) peut limiter le pouvoir de regroupement de \|.

\( … \)

est une construction de regroupement qui a trois utilités :

  1. pour entourer un jeu d'alternatives \| pour d'autres opérations. Ainsi, \(foo\|bar\)x correspond soit à foox, soit à barx.

  2. Pour entourer une expression complexe pour que les opérateurs suffixes *, + et ? agissent dessus. Ainsi, ba\(na\)* correspond à bananana, etc., avec un certain nombre (zéro ou plus) de chaînes na.

  3. Pour enregistrer une sous-chaîne correspondante pour une référence future.

Cette dernière application n'est pas une conséquence de l'idée de regroupement parenthésé ; c'est une caractéristique indépendante qui est assignée comme une seconde signification à la même construction \( … \). En pratique, il n'y a habituellement aucun conflit entre les deux significations ; lorsqu'il y a un conflit, vous pouvez utiliser un groupe "shy."

\(?: … \)

spécifie un groupe "shy" qui n'enregistre pas la sous-chaîne correspondante ; vous ne pouvez pas vous y référer avec \d. Ceci est utile dans des expressions rationnelles combinées mécaniquement, pour que vous puissiez ajouter des groupes à usages syntaxiques sans interférer avec la numérotation des groupes écrits par l'utilisateur.

\d

correspond au même texte correspondant avec la dième occurence d'une construction \( … \).

Après la fin d'une construction \( … \), la recherche de correspondance se souvient de la position de début et de fin du texte correspondant à cette construction. Alors, plus tard dans l'expression rationnelle, vous pouvez utiliser \ suivi du chiffre d pour dire "correspond au même texte correspondant la dième fois à la construction \( … \)."

Les chaînes correspondant aux neuf premières constructions \( … \) apparaissant dans une expression rationnelle se voient assigner les chiffres 1 à 9 dans l'ordre où les parenthèses ouvrantes sont apparues dans l'expression rationnelle. Vous pouvez alors utiliser de \1 à \9 pour référencer le texte coorespondant à la construction \( … \) associée.

Par exemple, \(.*\)\1 correspond à toute chaîne sans newline composée de deux moitiés identiques. \(.*\) correspond à la première moitié, qui peut être n'importe quoi, mais le \1 qui suit doit correspondre à exactement le même texte.

Si une construction \( … \) particulière correspond plus d'une fois (ce qui peut facilement arriver si elle est suivie de *), seule la dernière correspondance est sauvegardée.

\`

correspond à la chaîne vide, mais seulement au début du tampon ou de la chaîne à faire correspondre.

\'

correspond à la chaîne vide, mais seulement à la fin du tampon ou de la chaîne à faire correspondre.

\=

correspond à la chaîne vide, mais seulement au point.

\b

correspond à la chaîne vide, mais seulement au début ou à la fin d'un mot. Ainsi, \bfoo\b correspond à toute occurence de foo comme mot séparé. \bballs?\b correspond à ball ou balls comme mots.

\b correspond au début ou à la fin du tampon indépendamment du texte apparaissant près de lui.

\B

correspond à la chaîne vide, mais non au début ou à la fin d'un mot.

\<

correspond à la chaîne vide, mais seulement au début d'un mot. \< correspond au début du tampon seulement si un caractère constituant d'un mot le suit.

\>

correspond à la chaîne vide, mais seulement à la fin d'un mot. \> correspond à la fin du tampon seulement si le contenu finit avec un caractère constituant d'un mot.

\w

correspond à tout cractère constituant d'un mot. La table de syntaxe détermine quels caractères peuvent constituer un mot. Section 32.6.

\W

correspond à tout caractère non constituant d'un mot.

\sc

correspond à tout caractère dont la syntaxe est c. Ici c est un caractère qui représente un code de syntaxe : w pour contituant de mot, - pour caractère blanc, ( pour parenthèse ouvrante, etc. Représentez un caractère blanc (qui peut être un newline) par soit - soit un caractère espace.

\Sc

correspond à tout caractère dont la syntaxe n'est pas c.

\cc

correspond à tout caractère appartenant à la catégorie c. Par exemple, \cc correspond aux caractères chinois, \cg correspond aux caractères grecs, etc. Pour une description des catégories connues, tapez M-x describe-categories RET.

\Cc

correspond à tout caractère n'appartenant pas à la catégorie c.

Les constructions qui se rapportent à des mots et syntaxes sont contrôlées par la table de syntaxe (Section 32.6).

Voici une expression rationnelle complexe, utilisée par Emacs pour reconnaître la fin d'une phrase, avec les espaces qui la suivent. Elle est donnée dans la syntaxe Lisp pour vous permettre de distinguer les espaces des caractères tab. Dans la syntaxe Lisp, la constante chaîne commence et finit avec des guillemets. \" spécifie un guillemet dans la regexp, \\ une barre oblique inverse dans la regexp, t un caractère tab et \n un caractère newline.

"[.?!][]\"')]*\\($\\|\t\\|  \\)[ \t\n]*"

Elle contient quatre parties successives : un jeu de caractères correspondant à un point, ? ou ! ; un jeu de caractères correspondant à des crochets fermants, guillemets ou parenthèses, répétés un nombre quelconque de fois ; une alternative dans une construction de regroupement correspondant à une fin de ligne, un caractère tab ou deux espaces ; et un jeu de caractères correspondant à des caractères blancs, répétés un nombre quelconque de fois.

Pour entrer la même regexp interactivement, vous devrez taper TAB pour entrer un caractère tab, et C-j pour entrer un newline. Vous devrez aussi taper des barres obliques inverses simples, plutôt que de les doubler comme pour la syntaxe Lisp.