Les expressions régulières (ou regex) sont un mini-langage pour décrire des motifs de texte. Elles permettent de valider une adresse email, extraire tous les numéros de téléphone d'un document, nettoyer un fichier mal formaté... Python expose cette puissance via le module standard re. Les regex sont un sujet majeur du niveau Expert TOSA.
Premier contact
Le module re fournit des fonctions pour chercher/manipuler des motifs dans des chaînes.
import re
texte = "Contactez-nous au 04 90 12 34 56 ou au 06 11 22 33 44."
# Chercher tous les numéros de téléphone (format XX XX XX XX XX)
numeros = re.findall(r"\d{2} \d{2} \d{2} \d{2} \d{2}", texte)
print(numeros)En 5 caractères spéciaux (\d{2}), on a extrait tous les numéros. C'est la puissance des regex.
Pourquoi le r"..." ?
Le préfixe r (raw string) désactive l'interprétation des \ par Python. Sans lui, "\d" serait interprété par Python avant d'arriver à regex, et certains motifs casseraient.
Règle absolue : toujours utiliser r"..." pour écrire un motif regex.
Les caractères de base
Caractères littéraux
Dans un motif, la plupart des caractères représentent eux-mêmes.
import re
print(re.findall(r"chat", "le chat et le chien"))
print(re.findall(r"python", "Python n'est pas python")) # sensible à la casseCaractères spéciaux à connaître
Ces caractères ont un sens spécial et doivent être échappés avec \ pour être matchés littéralement :
. ^ $ * + ? { } [ ] ( ) \ |Exemple : pour chercher un vrai point, il faut \. :
import re
print(re.findall(r"\.", "fin. début."))Les classes de caractères
Une classe représente un caractère appartenant à un ensemble.
Classes prédéfinies
| Classe | Sens |
|---|---|
\d |
Un chiffre (0-9) |
\D |
Un non-chiffre |
\w |
Un caractère de mot : lettre, chiffre, underscore |
\W |
Un non-mot |
\s |
Un espace (espace, tabulation, newline...) |
\S |
Un non-espace |
. |
N'importe quel caractère (sauf \n par défaut) |
import re
texte = "Alice a 30 ans, Bob en a 25."
print(re.findall(r"\d", texte)) # chiffres isolés
print(re.findall(r"\w+", texte)) # mots entiersClasses personnalisées avec [...]
import re
# Un caractère parmi a, e, i, o, u
print(re.findall(r"[aeiou]", "bonjour"))
# Une plage : a-z, A-Z, 0-9
print(re.findall(r"[A-Z]", "Alice et Bob ont 30 ans"))
# Négation avec ^
print(re.findall(r"[^aeiou ]", "bonjour")) # ni voyelles ni espacesLes quantificateurs
Les quantificateurs indiquent combien de fois un motif peut se répéter.
| Quantificateur | Sens |
|---|---|
* |
0 ou plus |
+ |
1 ou plus |
? |
0 ou 1 (optionnel) |
{n} |
Exactement n fois |
{n,} |
Au moins n |
{n,m} |
Entre n et m |
import re
# 1 ou plusieurs chiffres
print(re.findall(r"\d+", "abc 123 def 4567"))
# Exactement 5 chiffres (code postal)
print(re.findall(r"\d{5}", "zip 75001 ou 69002 (mais pas 999)"))
# Entre 2 et 4 chiffres
print(re.findall(r"\d{2,4}", "1 22 333 4444 55555"))
# "Ah" avec 0 ou plus de "h" supplémentaires
print(re.findall(r"Ahh*", "Ah Ahh Ahhh Aaah"))Gourmandise : *?, +?, ??
Par défaut, les quantificateurs sont gourmands : ils matchent le maximum possible. Pour forcer une matching minimale, on ajoute un ?.
import re
texte = "<b>gras</b> et <i>italique</i>"
# Gourmand : capture TOUT jusqu'au dernier >
print(re.findall(r"<.+>", texte))
# Paresseux : s'arrête au premier >
print(re.findall(r"<.+?>", texte))