Les expressions régulières en Python (module re)
Une expression régulière (ou regex) est un motif qui décrit un ensemble de chaînes de caractères. En Python, tout passe par le module re de la bibliothèque standard : il permet de rechercher, extraire, valider et remplacer du texte avec une précision chirurgicale. Ce guide couvre le sujet de façon exhaustive : les fonctions principales (match, search, findall, sub), la syntaxe des motifs (classes, quantificateurs, ancres, groupes), les groupes nommés, les flags, et des exemples concrets comme la validation d’emails et l’extraction de dates.
Le module re et les chaînes brutes
On commence toujours par importer re. Les motifs s’écrivent dans des chaînes brutes (préfixe r"..."), qui empêchent Python d’interpréter les antislashs — essentiel car les regex en utilisent beaucoup.
import re
motif = r"\d+" # r"" = chaîne brute, \d n'est pas échappé par Python
texte = "Il y a 42 chats et 7 chiens"
resultat = re.findall(motif, texte)
print(resultat) # ['42', '7']
Sans le r, il faudrait écrire "\\d+". Prenez l’habitude d’utiliser r"..." systématiquement pour vos motifs.
re.search : trouver la première correspondance
re.search(motif, texte) parcourt toute la chaîne et renvoie un objet Match à la première correspondance, ou None si aucune.
import re
texte = "Commande n°A123 expédiée"
resultat = re.search(r"[A-Z]\d+", texte)
if resultat:
print(resultat.group()) # A123
print(resultat.start()) # 11 (position de départ)
L’objet Match est « vrai » dans un test if, ce qui rend la vérification très lisible.
re.match : ancrer au début
re.match ne teste le motif qu’au tout début de la chaîne. Il renvoie None si la correspondance n’est pas en position zéro.
import re
print(re.match(r"\d+", "123 abc")) # correspondance
print(re.match(r"\d+", "abc 123")) # None (ne commence pas par un chiffre)
Retenez la différence : match = « commence par », search = « contient quelque part ».
re.findall et re.finditer : toutes les correspondances
re.findall renvoie la liste de toutes les correspondances. re.finditer renvoie un itérateur d’objets Match, utile quand on a besoin des positions.
import re
texte = "prix : 12€, 8€ et 150€"
print(re.findall(r"\d+", texte)) # ['12', '8', '150']
for m in re.finditer(r"\d+", texte):
print(m.group(), "à la position", m.start())
Attention : si le motif contient des groupes (...), findall renvoie les groupes et non la correspondance complète — un piège fréquent que nous illustrons plus bas.
re.sub : remplacer
re.sub(motif, remplacement, texte) remplace toutes les correspondances par la chaîne fournie.
import re
texte = "Contactez-nous au 06 12 34 56 78 svp"
masque = re.sub(r"\d", "X", texte)
print(masque) # Contactez-nous au XX XX XX XX XX svp
Le remplacement peut aussi être une fonction, pour un traitement dynamique :
import re
def majuscule(m):
return m.group().upper()
print(re.sub(r"\b\w", majuscule, "bonjour le monde")) # Bonjour Le Monde
La syntaxe des motifs : classes de caractères
Une classe de caractères décrit un ensemble de caractères acceptables.
Les classes prédéfinies
\d: un chiffre (0-9)\w: un caractère de mot (lettre, chiffre, underscore)\s: un espace, une tabulation ou un retour à la ligne.: n’importe quel caractère (sauf saut de ligne)
Leurs versions majuscules \D, \W, \S désignent l’inverse.
import re
print(re.findall(r"\w+", "hello_42 monde !")) # ['hello_42', 'monde']
print(re.findall(r"\S+", "a b c")) # ['a', 'b', 'c']
Les classes personnalisées avec [ ]
Entre crochets, on définit son propre ensemble. Un tiret indique un intervalle, un ^ en tête signifie la négation.
import re
print(re.findall(r"[aeiou]", "programmation")) # voyelles
print(re.findall(r"[A-Za-z]+", "Python 3.12")) # ['Python']
print(re.findall(r"[^0-9]", "a1b2")) # tout sauf des chiffres
Les quantificateurs
Ils indiquent combien de fois l’élément précédent doit apparaître.
*: zéro fois ou plus+: une fois ou plus?: zéro ou une fois (optionnel){n}: exactement n fois{n,m}: entre n et m fois
import re
print(re.findall(r"ab*", "a ab abb abbb")) # ['a', 'ab', 'abb', 'abbb']
print(re.findall(r"\d{2,4}", "1 22 333 44444")) # ['22', '333', '4444']
Par défaut les quantificateurs sont gloutons (ils prennent le maximum). Ajouter ? les rend paresseux :
import re
print(re.findall(r"<.*>", "<a><b>")) # ['<a><b>'] (glouton)
print(re.findall(r"<.*?>", "<a><b>")) # ['<a>', '<b>'] (paresseux)
Les ancres
Les ancres ne correspondent pas à des caractères mais à des positions.
^: début de chaîne (ou de ligne avec le flag MULTILINE)$: fin de chaîne\b: frontière de mot
import re
print(re.search(r"^Bonjour", "Bonjour tout le monde")) # correspond
print(re.search(r"monde$", "Bonjour le monde")) # correspond
print(re.findall(r"\bchat\b", "chat chaton chat")) # ['chat', 'chat']
Le \b évite ici de capturer « chat » à l’intérieur de « chaton ».
Les groupes de capture
Les parenthèses (...) créent un groupe dont on peut récupérer le contenu séparément avec .group(n).
import re
texte = "2025-12-02"
m = re.search(r"(\d{4})-(\d{2})-(\d{2})", texte)
print(m.group(0)) # 2025-12-02 (correspondance complète)
print(m.group(1)) # 2025 (année)
print(m.group(2)) # 12 (mois)
print(m.groups()) # ('2025', '12', '02')
Les groupes nommés
Pour un code plus lisible, on nomme les groupes avec (?P<nom>...) et on y accède par leur nom.
import re
texte = "2025-12-02"
m = re.search(r"(?P<annee>\d{4})-(?P<mois>\d{2})-(?P<jour>\d{2})", texte)
print(m.group("annee")) # 2025
print(m.group("mois")) # 12
print(m.groupdict()) # {'annee': '2025', 'mois': '12', 'jour': '02'}
C’est particulièrement précieux dans les motifs complexes où compter les parenthèses devient pénible.
Les flags
Les flags modifient le comportement global du motif. On les passe en dernier argument.
re.IGNORECASE(oure.I) : ignore la cassere.MULTILINE(re.M) :^et$s’appliquent à chaque lignere.DOTALL(re.S) :.inclut aussi les sauts de ligne
import re
print(re.findall(r"python", "Python PYTHON python", re.IGNORECASE))
# ['Python', 'PYTHON', 'python']
texte = "ligne1\nligne2\nligne3"
print(re.findall(r"^ligne\d", texte, re.MULTILINE))
# ['ligne1', 'ligne2', 'ligne3']
Compiler un motif avec re.compile
Si vous réutilisez un même motif de nombreuses fois, re.compile le pré-compile une seule fois et améliore la lisibilité.
import re
motif_tel = re.compile(r"\d{2} \d{2} \d{2} \d{2} \d{2}")
for ligne in ["06 12 34 56 78", "rien ici"]:
if motif_tel.search(ligne):
print("Numéro trouvé :", ligne)
Exemple complet n°1 : valider un email
Un motif d’email pragmatique (aucune regex ne couvre parfaitement la norme, mais celle-ci suffit largement en pratique).
import re
motif_email = re.compile(r"^[\w.+-]+@[\w-]+\.[\w.-]+$")
for adresse in ["[email protected]", "invalide@", "[email protected]"]:
if motif_email.match(adresse):
print(adresse, "→ valide")
else:
print(adresse, "→ invalide")
Exemple complet n°2 : extraire des dates
On extrait toutes les dates au format JJ/MM/AAAA d’un texte, avec des groupes nommés.
import re
texte = "Réunion le 02/12/2025, livraison le 15/01/2026."
motif = re.compile(r"(?P<jour>\d{2})/(?P<mois>\d{2})/(?P<annee>\d{4})")
for m in motif.finditer(texte):
print(f"{m.group('jour')}-{m.group('mois')}-{m.group('annee')}")
Sortie :
02-12-2025
15-01-2026
Conclusion
Le module re couvre tous les besoins de manipulation de texte par motif : search et match pour trouver, findall et finditer pour tout collecter, sub pour remplacer. Maîtrisez les classes de caractères, les quantificateurs et les groupes (nommés de préférence), et vous validerez emails, dates ou numéros de téléphone en quelques lignes. Pour des transformations plus simples, pensez aussi aux méthodes natives présentées dans notre guide sur la manipulation de chaînes en Python.