
Syntaxe des expressions régulières (caractères spéciaux, quantificateurs...)
Maîtrisez la syntaxe des expressions régulières en Python. Découvrez la signification des caractères spéciaux (. * + ? [] ^ $ \ | ()), des quantificateurs ({}, *, +, ?), des classes de caractères, et des séquences spéciales.
Caractères littéraux et caractères spéciaux (métacaractères)
Dans une expression régulière, la plupart des caractères se représentent eux-mêmes. Par exemple, le motif `abc` correspond simplement à la chaîne "abc".
Cependant, certains caractères ont une signification spéciale. Ce sont les *caractères spéciaux* (ou *métacaractères*) : `.^$*+?{}[]\|()`. Pour utiliser ces caractères littéralement, vous devez les *échapper* en les précédant d'un antislash (`\`).
Exemple :
import re
# Pour rechercher le caractère '.' (point), il faut l'échapper :
texte = "Un point, c'est tout."
motif = "\."
resultat = re.search(motif, texte) # Trouve le point
# Sans l'échappement, '.' correspondrait à n'importe quel caractère :
motif = "." # Correspond à 'U', 'n', ' ', 'p', ...
# Pour rechercher une accolade ouvrante : \{
# Pour rechercher un antislash : \\Classes de caractères : [] et [^]
Les crochets `[]` permettent de définir une *classe de caractères*, c'est-à-dire un ensemble de caractères possibles.
- `[abc]` : Correspond à `a`, `b`, ou `c`.
- `[a-z]` : Correspond à n'importe quelle lettre minuscule (de `a` à `z`).
- `[A-Z]` : Correspond à n'importe quelle lettre majuscule.
- `[0-9]` : Correspond à n'importe quel chiffre.
- `[a-zA-Z0-9]` : Correspond à n'importe quelle lettre (minuscule ou majuscule) ou chiffre.
A l'intérieur de crochets, la plupart des caractères spéciaux perdent leur signification spéciale et sont interprétés littéralement (sauf `^`, `-`, `]` et `\`).
Le `^` (circonflexe), placé *immédiatement après le crochet ouvrant*, a une signification spéciale : il *inverse* la classe de caractères.
- `[^abc]` : Correspond à n'importe quel caractère *sauf* `a`, `b`, ou `c`.
- `[^0-9]` : Correspond à n'importe quel caractère qui n'est *pas* un chiffre.
Exemples :
import re
# Trouver une voyelle
texte = "Bonjour"
motif = "[aeiouyAEIOUY]"
resultat = re.search(motif, texte)
print(resultat.group(0)) # Affiche 'o'
# Trouver un caractère non alphanumérique
texte = "Hello_World!123"
motif = "[^a-zA-Z0-9_]"
resultat = re.search(motif, texte) # Trouve '!'
print(resultat.group(0))Quantificateurs : *, +, ?, {}
Les *quantificateurs* permettent de spécifier le nombre de répétitions d'un caractère, d'un groupe, ou d'une classe de caractères.
- `*` (astérisque) : Zéro, une ou plusieurs répétitions de l'élément précédent.
- `+` (plus) : Une ou plusieurs répétitions de l'élément précédent.
- `?` (point d'interrogation) : Zéro ou une répétition de l'élément précédent.
- `{n}` : Exactement `n` répétitions de l'élément précédent.
- `{n,}` : Au moins `n` répétitions de l'élément précédent.
- `{n,m}` : Entre `n` et `m` répétitions (inclus) de l'élément précédent.
Exemples :
import re
# "ab*" : 'a' suivi de zéro, une ou plusieurs occurrences de 'b'
print(re.search(r"ab*", "a")) # Trouve 'a'
print(re.search(r"ab*", "ab")) # Trouve 'ab'
print(re.search(r"ab*", "abbb")) # Trouve 'abbb'
# "ab+" : 'a' suivi d'au moins une occurrence de 'b'
print(re.search(r"ab+", "a")) # None
print(re.search(r"ab+", "ab")) # Trouve 'ab'
# "ab?" : 'a' suivi de zéro ou une occurrence de 'b'
print(re.search(r"ab?", "a")) # Trouve 'a'
print(re.search(r"ab?", "ab")) # Trouve 'ab'
print(re.search(r"ab?", "abbb")) # Trouve 'ab' (le premier)
# "a{3}" : exactement 3 'a'
print(re.search(r"a{3}", "aa")) # None
print(re.search(r"a{3}", "aaa")) # Trouve 'aaa'
# "a{2,}" : au moins 2 'a'
print(re.search(r"a{2,}", "a")) # None
print(re.search(r"a{2,}", "aa")) # Trouve 'aa'
print(re.search(r"a{2,}", "aaaaa")) # Trouve 'aaaaa'
# "a{2,4}" : entre 2 et 4 'a'
print(re.search(r"a{2,4}", "a")) # None
print(re.search(r"a{2,4}", "aa")) # Trouve 'aa'
print(re.search(r"a{2,4}", "aaaa")) # Trouve 'aaaa'
print(re.search(r"a{2,4}", "aaaaa")) # Trouve 'aaaa' (les 4 premiers)Par défaut, les quantificateurs sont "gourmands" (greedy), c'est-à-dire qu'ils essaient de correspondre à la plus grande séquence possible. Vous pouvez les rendre "non gourmands" (lazy) en ajoutant un `?` après le quantificateur (par exemple, `*?`, `+?`, `??`, `{n,}?`).
Le point (.) : n'importe quel caractère (sauf saut de ligne)
Le point `.` (dans le mode par défaut) correspond à *n'importe quel caractère*, sauf un saut de ligne (`\n`).
Exemple :
import re
# ".+" : un ou plusieurs caractères quelconques
print(re.search(r".+", "Bonjour le monde")) # Trouve toute la chaîne
# "a.c" : 'a', suivi d'un caractère quelconque, suivi de 'c'
print(re.search(r"a.c", "abc")) # Trouve 'abc'
print(re.search(r"a.c", "a1c")) # Trouve 'a1c'
print(re.search(r"a.c", "ac")) # NoneSi vous voulez que le point corresponde *aussi* aux sauts de ligne, vous pouvez utiliser le flag `re.DOTALL` (voir la section sur les fonctions du module `re`).
Ancres : ^ et $ (début et fin de chaîne)
- `^` (circonflexe) : Correspond au *début* de la chaîne (ou au début de chaque ligne, en mode multiligne).
- `$` (dollar) : Correspond à la *fin* de la chaîne (ou à la fin de chaque ligne, en mode multiligne).
Exemples :
import re
# "^Bonjour" : la chaîne doit commencer par "Bonjour"
print(re.search(r"^Bonjour", "Bonjour le monde")) # Trouve
print(re.search(r"^Bonjour", "Le monde Bonjour")) # None
# "monde$" : la chaîne doit se terminer par "monde"
print(re.search(r"monde$", "Bonjour le monde")) # Trouve
print(re.search(r"monde$", "Le monde Bonjour")) # NoneAlternation : | (OU logique)
La barre verticale `|` permet de spécifier une alternative (un choix entre plusieurs motifs).
Exemple :
import re
# "chat|chien" : correspond à "chat" ou "chien"
print(re.search(r"chat|chien", "J'ai un chat.")) # Trouve 'chat'
print(re.search(r"chat|chien", "J'ai un chien.")) # Trouve 'chien'
print(re.search(r"chat|chien", "J'ai un oiseau.")) # NoneGroupes : ()
Les parenthèses `()` permettent de grouper des parties d'une expression régulière.
Les groupes ont plusieurs utilités :
- Appliquer un quantificateur à un groupe : Par exemple, `(ab)+` correspond à une ou plusieurs répétitions de la séquence "ab".
- Définir des alternatives à l'intérieur d'un groupe : Par exemple, `(a|b)c` correspond à "ac" ou "bc".
- Capturer des groupes : Par défaut, les groupes sont *capturants*, ce qui signifie que la partie de la chaîne qui correspond au groupe est mémorisée et peut être récupérée ultérieurement (voir la section sur les fonctions du module `re`).
- Faire référence à un groupe capturé plus tôt dans l'expression régulière (backreferences, voir plus loin).
Exemple :
import re
# "(ab)+" : une ou plusieurs répétitions de "ab"
print(re.search(r"(ab)+", "ab")) # Trouve 'ab'
print(re.search(r"(ab)+", "ababab")) # Trouve 'ababab'
print(re.search(r"(ab)+", "ac")) # None
# "(a|b)c" : 'a' ou 'b', suivi de 'c'
print(re.search(r"(a|b)c", "ac")) # Trouve 'ac'
print(re.search(r"(a|b)c", "bc")) # Trouve 'bc'
print(re.search(r"(a|b)c", "dc")) # NoneSéquences spéciales : \d, \w, \s, etc.
Python définit plusieurs *séquences spéciales* qui représentent des ensembles de caractères courants. Ces séquences spéciales commencent par un antislash `\` suivi d'une lettre.
Voici quelques séquences spéciales courantes :
- `\d` : Correspond à n'importe quel chiffre (équivalent à `[0-9]`).
- `\D` : Correspond à n'importe quel caractère qui n'est *pas* un chiffre (équivalent à `[^0-9]`).
- `\w` : Correspond à n'importe quel caractère alphanumérique (lettres, chiffres, et le trait de soulignement `_`) (équivalent à `[a-zA-Z0-9_]` pour les chaînes ASCII). Dans les chaînes Unicode, correspond aussi aux caractères considérés comme des lettres ou des chiffres dans d'autres alphabets.
- `\W` : Correspond à n'importe quel caractère qui n'est *pas* alphanumérique.
- `\s` : Correspond à n'importe quel caractère "blanc" (espace, tabulation, saut de ligne, etc.).
- `\S` : Correspond à n'importe quel caractère qui n'est *pas* un caractère "blanc".
- `\b` : Correspond à une limite de mot (word boundary), c'est à dire entre un caractère `\w` et un caractère `\W`, ou entre un caractère `\w` et le début/fin de la chaîne.
- `\B` : Correspond à une position qui n'est *pas* une limite de mot.
Exemples :
import re
# "\d+" : un ou plusieurs chiffres
print(re.search(r"\d+", "Il y a 123 pommes.")) # Trouve '123'
# "\w+" : un ou plusieurs caractères alphanumériques (un "mot")
print(re.search(r"\w+", "Bonjour le_monde!")) # Trouve 'Bonjour'
# "\s+" : un ou plusieurs espaces
print(re.search(r"\s+", "Bonjour le monde")) # Trouve ' ' (les trois espaces)Ces séquences spéciales peuvent être utilisées à l'intérieur ou à l'extérieur des classes de caractères (`[]`).
Echappement : \
L'antislash `\` a une double fonction dans les expressions régulières :
- Il permet d'échapper les caractères spéciaux pour qu'ils soient interprétés littéralement (par exemple, `\.` pour rechercher un point, `\*` pour rechercher une astérisque, `\(` pour une parenthèse ouvrante, etc.).
- Il introduit les séquences spéciales (comme `\d`, `\w`, `\s`, etc.).
Si vous voulez rechercher un antislash littéral, vous devez l'échapper lui-même : `\\`.
Exemple :
import re
# Rechercher une chaîne contenant un point (échappé)
print(re.search(r"\.", "abc.def")) # Trouve '.'
# Rechercher une chaîne contenant un antislash (échappé)
print(re.search(r"\\", "a\\b")) # Trouve '\\'Pour éviter d'avoir à échapper les antislashs eux-mêmes, vous pouvez utiliser des *chaînes brutes* (raw strings) pour définir vos expressions régulières. Une chaîne brute est préfixée par un `r` (ou `R`) avant le guillemet ouvrant. Dans une chaîne brute, les antislashs sont interprétés littéralement.
Exemple (avec une chaîne brute) :
import re
# Rechercher une chaîne contenant un antislash (avec une chaîne brute)
print(re.search(r"\", "a\b")) # Trouve '\\'Il est *fortement recommandé* d'utiliser des chaînes brutes pour définir vos expressions régulières en Python, pour éviter les confusions et les erreurs liées à l'échappement des antislashs.
Quantificateurs non gourmands (lazy)
Par défaut, les quantificateurs (`*`, `+`, `?`, `{}`) sont "gourmands" (greedy). Cela signifie qu'ils essaient de correspondre à la plus *longue* chaîne possible.
Vous pouvez rendre un quantificateur "non gourmand" (lazy, ou minimal) en ajoutant un `?` après le quantificateur.
Un quantificateur non gourmand essaie de correspondre à la plus *courte* chaîne possible.
Exemple :
import re
texte = "texte 1 et texte 2"
# Gourmand (greedy) : correspond au plus long possible
motif_gourmand = r"<.+>"
print(re.search(motif_gourmand, texte).group(0)) # texte 1 et texte 2
# Non gourmand (lazy) : correspond au plus court possible
motif_non_gourmand = r"<.+?>"
print(re.search(motif_non_gourmand, texte).group(0)) #
Dans cet exemple, le motif gourmand `<.+>` correspond à toute la chaîne entre la *première* balise ouvrante `<` et la *dernière* balise fermante `>`. Le motif non gourmand `<.+?>` correspond à la plus courte chaîne possible entre `<` et `>`, c'est-à-dire la première balise ouvrante ``.
Les quantificateurs non gourmands sont : `*?`, `+?`, `??`, `{n,}?`.