Grimoire-
Command
.es

GNU+Linux command memo

Memo_7 : Expressions régulières (ou rationnelles)

D’après l’édition 11 des travaux d’Alain Leaper, 2018-04-10
Mis à jour le 2020-02-19
Licence GPL

Les expressions régulières (ou regular expressions) sont constituées de 2 sortes de caractères:

  • les caractères "ordinaires", notamment : a à z, A à Z, 0 à 9

  • les caractères interprétés avec un sens "spécial" (métacaractères)

Les métacaractères peuvent redevenir des caractères ordinaires s’il sont précédés du métacaractères \ (anti-slash, ou backslash). Par exemple \* dans une expression régulière redevient * , \\ lui-même redevient \. C’est le mécanisme d’échappement, déjà aperçu dans les Memo_4 et Memo_5.

Selon le contexte d’utilisation (utilitaires, shell) certains caractères peuvent être des métacaractères ou non. C’est notamment le cas pour / et !. À l’inverse, il peut être nécessaire d’échapper un métacaractère pour qu’il soit reconnu en tant que tel. Voir à la fin: "Remarque importante".

1. Les métacaractères

  • ^ spécifie le début d’une ligne

  • $ spécifie la fin d’une ligne

  • . (point): peut remplacer n’importe quel caractère ordinaire

  • * spécifie un nombre quelconque (y compris nul) d’occurrences du caractère qui le précède

  • ? spécifie zéro ou une occurrence du caractère qui le précède

  • + spécifie une ou plus occurrence(s) du caractère qui le précède

  • {n} spécifie n occurrences du caractère qui le précède

  • {n,p} le nombre d’occurrences doit être compris entre n et p (inclus)

  • {n,} le nombre d’occurrences doit être supérieur ou égal à n

{0,1} est équivalent à ? {1,} est équivalent à + {0,} est équivalent à *

Remarque : contrairement à la reconnaissance d’un minimum de caractères, le filtrage sur un maximum (ou sur l’égalité) doit être borné devant et derrière le critère de sélection.

au{2,3}q (1)
u{2,3}q (2)
au{2,3} (2)
1 Correct : seront reconnus "auuq", "auuuq" mais pas "auuuuuq"
2 Incorrect : "auuuuq" …​ seront reconnus

Par contre, si on désire filtrer sur un minimum d’occurrences : u{4} reconnaitra n’importe quelle séquence qui comporte au moins 4 'u' consécutifs.

1.1. [] spécifie un ensemble de possibilités de remplacement d'un caractère

s[k3v]j

Peut spécifier skj ou s3j ou svj

Il est possible de spécifier une (ou des) plage(s) de remplacement :

  • s[I-L]j est équivalent à s[IJKL]j

  • f[3-5I-L]v est équivalent à f[345IJKL]v

1.2. [a-zA-Z0-9] spécifie l’ensemble des caractères alphanumériques

En dehors de cette utilisation (entre []), le tiret "-" n’est pas un métacaractère.

1.3. [^, indique la négation de l’ensemble

^ derrière [, à ne pas confondre avec ^ de début de ligne.

Ainsi s[^k3v]j ne trouvera ni skj, ni s3j, ni svj.

[^a-z0-9] élimine l’ensemble des minuscules et des chiffres.

1.4. () permet de délimiter des sous-expressions (séquence de caractères)

Avec des sous-expressions il est possible d’effectuer une recherche ordonnée selon leur rang sur la ligne par \n. n désignant le rang sur la ligne. Voir "Remarque importante".

1.5. | signifie ou entre les expressions qui se trouvent de part et d’autre

Exemple : U(axz)|(lgt)Z reconnaît à la fois Uaxz et UlgtZ

[abcd]|[123] est équivalent à [abcd123]

L’utilisation de parenthèses permet aussi de distinguer une hiérarchie de sous-expressions. Par exemple : toutes le lignes qui commencent par 'axt' ou par 'vcr' seront trouvées par ^((axt)|(vcr)).*.

L’usage de la négation par ^ est réservé aux ensembles (pas aux sous-expressions). Ainsi, par exemple, pour éliminer les lignes qui commencent par '->', on peut utiliser l’artifice :

$ grep -E '^([^\-][^>])' (1)
$ grep '^\([^\-][^>]\)' (2)
1 À l’intérieur des [], \- redevient le caractère ordinaire '-'. L’option -E de grep quand à elle permet de traiter des expressions régulières étendues (voir grep : Memo_6).
2 Avec une expression régulière simple
Cette opération élimine également les lignes vides, ce qui n’est pas forcément souhaité !

2. Expression régulières simples et étendues

Pour être reconnu dans une expression régulière simple, certains caractères spéciaux doivent être précédés d’un \. Ce qui n’est pas le cas pour expression régulière étendue.

Expressions régulières simples

Expressions régulières étendues

\+

+

\?

?

\|

|

\{

{

\}

}

\(

[

\)

)

Les autres (., $, *, ^, [, etc.) sont traités de la même manière.

3. Stratégie de recherche d’un filtre en utilisant grep ou sed

Problème: on désire rapidement savoir si une expression régulière va reconnaître la bonne expression.

Le plus simple est d’utiliser le canal d’entrée standard par défaut (donc le clavier).

Exemple: on recherche les lignes commençant par z, finissant par un chiffre et comportant, entre 5 et 7 caractères (3 à 5 entre le premier et le dernier) :

$ grep --color -E '^z.{3,5}[0-9]$' (1)
zdsf4 (1)
zdsf4 (2)
zfdgfhjgkhl5 (3)
z1234 (1)
z1234 (2)
zjl2  (3)
zgghjl (3)
zgghj0 (1)
zgghj0 (2)
(4)
1 Saisie puis Entrée
2 chaîne reconnue ré-écrite en rouge dans la console
3 Entrée mais la chaîne n’est pas reconnue, donc pas reproduite
4 Ctrl+D pour sortir.

Résultat: seules les lignes répondant au critère de filtrage sont transmises au canal de sortie standard, l’écran par défaut.

4. Remarque importante

Selon les utilitaires, les métacaractères ne sont pas toujours traités de la même manière. Pour être reconnu en tant que métacaractères, il peut être nécessaire de les faire précéder d’un \.

sed n’utilise pas les expressions régulières étendues, seulement les expressions régulières simples.

grep peut utiliser les deux, selon l’option -E

vi utilise par défaut les expressions régulières simples, comme nous l’avons vu ici replace text vim.

4.1. Premier exemple : avec sed, le ? doit être échappé

Avec sed, ? doit être échappé (idem pour +, mais pas pour . ni *)

$ sed -n -e '/^AbCh\?t$/p'
AbCht (1)
AbCht (2)
AbChht (3)
AbCt (1)
AbCt (4)
1 Saisie puis Entrée
2 Une occurrence de 'h' : motif reconnu
3 2 occurrences de 'h' : motif non reconnu
4 aucune occurrence de 'h' : motif reconnu
$ sed -n -e '/^AbCh?t$/p'
AbCht (1)
1 une occurrence de h : motif non reconnu !

Avec grep : il ne faut pas \? (? seulement) et option -E (pour expressions régulières étendues).

$ grep -E '^AbCh?t$'
AbCht (1)
AbCht (2)
AbChhhht (3)
1 Saisie puis Entrée
2 une occurrence de h : motif reconnu et ré-affiché
3 Entrée, 4 occurrences de h : motif non reconnu

4.2. Deuxième exemple : filtrer un motif commençant par 'a' suivi de 3 lettres identiques, suivi de 'b'

Avec sed les () des sous-expressions doivent être précédées de \ → \( \)

$ sed -n -e '/a\(.\+\)\1\1b/p'
xyzatttbghi (1)
xyzatttbghi (2)
1 Saisie puis Entrée
2 Motif reconnu

Avec grep : pas de \ devant (), ni devant + (option -E, expressions régulières étendues) :

$ grep -E 'a(.+)\1\1b'
xyzatttbghi (1)
xyzatttbghi (2)
1 Saisie puis Entrée
2 Motif reconnu