Skip to main content

Code that compiles on the first try! CodeWithMpia wishes you very happy holidays.✨

Aller au contenu principal

Les expressions régulières en Python : Le guide complet pour enfin comprendre les regex

Après des années à redouter ces suites de symboles illisibles et à copier-coller des patterns venus de Stack Overflow, ce guide complet sur les expressions régulières en Python est enfin là pour t’aider à apprivoiser les regex une bonne fois pour toutes.

M
Mpia
12/17/2025 57 min
84 vues
0 comme.
#Python#Code#Regex#Re
Les expressions régulières en Python : Le guide complet pour enfin comprendre les regex

Les regex font partie de ces sujets qui terrorisent les développeurs débutants. Vous voyez passer des trucs comme ^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$ et vous vous dites "non merci, je passe mon tour" ?

Si vous avez déjà copié-collé une regex depuis Stack Overflow sans comprendre ce qu'elle fait (on l'a tous fait 😅), cet article est pour vous.

Les expressions régulières, c'est comme apprendre à lire une nouvelle langue. Au début, c'est du charabia. Puis, petit à petit, vous commencez à reconnaître des motifs. Et un jour, vous écrivez vos propres regex sans même y penser.

Dans ce guide, on va apprendre les regex en pratique, avec des exemples concrets et des situations réelles que vous allez rencontrer.

Ce que vous allez apprendre :

  • C'est quoi une expression régulière et pourquoi c'est utile

  • La syntaxe de base expliquée simplement

  • Le module re de Python en détail

  • Des exemples pratiques (emails, téléphones, URLs, etc.)

  • Les pièges à éviter

  • Les bonnes pratiques pour écrire des regex lisibles

Partie 1 : Comprendre les regex (la théorie simple)

C'est quoi une expression régulière ?

Imaginez que vous cherchez un mot dans un livre. Facile : Ctrl+F et c'est réglé. Mais que faire si vous cherchez :

  • Tous les numéros de téléphone ?

  • Toutes les adresses email ?

  • Tous les mots qui commencent par "anti" ?

  • Toutes les dates au format JJ/MM/AAAA ?

C'est là que les regex entrent en jeu.

Une expression régulière (regex, regexp) est un motif de recherche. C'est une façon de décrire "à quoi ressemble" ce que vous cherchez.

Avec les regex, vous pouvez :

  • Rechercher des motifs complexes dans du texte

  • Valider des données (email valide ? téléphone correct ?)

  • Extraire des informations spécifiques

  • Remplacer du texte intelligemment

  • Découper des chaînes de caractères

Pourquoi apprendre les regex ?

Les regex sont partout :

  • Validation de formulaires web

  • Traitement de fichiers logs

  • Web scraping

  • Nettoyage de données

  • Recherche dans des éditeurs de code (VS Code, Sublime Text)

  • Commandes Unix (grep, sed, awk)

  • Bases de données (SQL LIKE avancé)

Sans regex :

# Vérifier si une chaîne contient un email... sans regex
def contient_email(texte):
    # Bonne chance pour écrire ça proprement !
    # Il faudrait vérifier le @, le point, les caractères valides...
    # C'est un cauchemar
    pass

Avec regex :

import re

def contient_email(texte):
    pattern = r'[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+'
    return bool(re.search(pattern, texte))

Une ligne. Terminé.

Le module re de Python

Python inclut le module re dans sa bibliothèque standard. Pas besoin d'installer quoi que ce soit !

import re

# C'est tout ce qu'il faut pour commencer

Partie 2 : La syntaxe de base

Les caractères littéraux

Le plus simple : chercher un mot exact.

import re

texte = "Python est un langage de programmation"

# Chercher "Python"
resultat = re.search("Python", texte)
print(resultat)  # <re.Match object; span=(0, 6), match='Python'>

# Chercher "Java"
resultat = re.search("Java", texte)
print(resultat)  # None (pas trouvé)

Note : Les regex sont sensibles à la casse par défaut.

re.search("python", "Python est cool")  # None
re.search("Python", "Python est cool")  # Match !

Les métacaractères (les caractères spéciaux)

Voici où ça devient intéressant. Certains caractères ont une signification spéciale :

.  ^  $  *  +  ?  {  }  [  ]  \  |  (  )

Le point . : N'importe quel caractère

import re

# Le point matche n'importe quel caractère (sauf \n)
re.search("p.thon", "python")   # Match ! (y = n'importe quel caractère)
re.search("p.thon", "pothon")   # Match !
re.search("p.thon", "p thon")   # Match ! (espace aussi)
re.search("p.thon", "pthon")    # None (il faut UN caractère)

L'accent circonflexe ^ : Début de chaîne

re.search("^Bonjour", "Bonjour le monde")  # Match !
re.search("^Bonjour", "Dire Bonjour")      # None (pas au début)

Le dollar $ : Fin de chaîne

re.search("monde$", "Bonjour le monde")  # Match !
re.search("monde$", "monde cruel")       # None (pas à la fin)

Combiner ^ et $ : Chaîne entière

# La chaîne doit être EXACTEMENT "Python"
re.search("^Python$", "Python")              # Match !
re.search("^Python$", "Python est cool")     # None
re.search("^Python$", "J'aime Python")       # None

Les quantificateurs

L'étoile * : Zéro ou plus

# "a" suivi de zéro ou plusieurs "b"
re.search("ab*", "a")       # Match ! (a + 0 b)
re.search("ab*", "ab")      # Match ! (a + 1 b)
re.search("ab*", "abbbb")   # Match ! (a + 4 b)
re.search("ab*", "b")       # None (pas de "a")

Le plus + : Un ou plus

# "a" suivi de un ou plusieurs "b"
re.search("ab+", "a")       # None (il faut au moins 1 b)
re.search("ab+", "ab")      # Match ! (a + 1 b)
re.search("ab+", "abbbb")   # Match ! (a + 4 b)

Le point d'interrogation ? : Zéro ou un

# "a" suivi de zéro ou un "b"
re.search("ab?", "a")       # Match ! (a + 0 b)
re.search("ab?", "ab")      # Match ! (a + 1 b)
re.search("ab?", "abb")     # Match ! (mais seulement "ab")

Les accolades {n} : Exactement n fois

# Exactement 3 "a"
re.search("a{3}", "aa")       # None
re.search("a{3}", "aaa")      # Match !
re.search("a{3}", "aaaa")     # Match ! (les 3 premiers)

# Entre 2 et 4 "a"
re.search("a{2,4}", "a")      # None
re.search("a{2,4}", "aa")     # Match !
re.search("a{2,4}", "aaaa")   # Match !
re.search("a{2,4}", "aaaaa")  # Match ! (les 4 premiers)

# Au moins 2 "a"
re.search("a{2,}", "a")       # None
re.search("a{2,}", "aa")      # Match !
re.search("a{2,}", "aaaaaa")  # Match !

Les classes de caractères []

Les crochets définissent un ensemble de caractères possibles.

# Matcher "a" OU "e" OU "i" OU "o" OU "u"
re.search("[aeiou]", "python")   # Match ! (le 'o')
re.search("[aeiou]", "xyz")      # None

# Plages de caractères
re.search("[a-z]", "Hello")      # Match ! (le 'e')
re.search("[A-Z]", "Hello")      # Match ! (le 'H')
re.search("[0-9]", "Python3")    # Match ! (le '3')

# Combinaisons
re.search("[a-zA-Z]", "123abc")  # Match ! (le 'a')
re.search("[a-zA-Z0-9]", "!")    # None

Négation avec ^ (dans les crochets) :

# N'importe quel caractère SAUF a, e, i, o, u
re.search("[^aeiou]", "aaa")     # None
re.search("[^aeiou]", "abc")     # Match ! (le 'b')
re.search("[^0-9]", "123")       # None
re.search("[^0-9]", "12a3")      # Match ! (le 'a')

Les séquences spéciales

Python offre des raccourcis pratiques :

Séquence Signification Équivalent
\d Chiffre [0-9]
\D Non-chiffre [^0-9]
\w Alphanumérique [a-zA-Z0-9_]
\W Non-alphanumérique [^a-zA-Z0-9_]
\s Espace blanc [ \t\n\r\f\v]
\S Non-espace [^ \t\n\r\f\v]
\b Limite de mot -
\B Non-limite de mot -
# Exemples pratiques
re.search(r"\d+", "J'ai 25 ans")       # Match ! '25'
re.search(r"\w+", "Bonjour!")          # Match ! 'Bonjour'
re.search(r"\s+", "Hello World")       # Match ! ' ' (l'espace)

# Limite de mot (très utile !)
re.search(r"\bcat\b", "cat")           # Match !
re.search(r"\bcat\b", "category")      # None (cat fait partie d'un mot)
re.search(r"\bcat\b", "the cat sat")   # Match !

Important : Le r devant la chaîne !

Utilisez toujours r"..." (raw string) pour les regex en Python. Ça évite les problèmes d'échappement.

# Sans r : problème potentiel
re.search("\bcat\b", "cat")   # Ne marche pas comme prévu !

# Avec r : correct
re.search(r"\bcat\b", "cat")  # Match !

L'alternation | (OU)

# Matcher "chat" OU "chien"
re.search(r"chat|chien", "J'ai un chat")    # Match ! 'chat'
re.search(r"chat|chien", "J'ai un chien")   # Match ! 'chien'
re.search(r"chat|chien", "J'ai un lapin")   # None

Les groupes ()

Les parenthèses servent à grouper et capturer.

# Grouper pour appliquer un quantificateur
re.search(r"(ab)+", "ababab")     # Match ! 'ababab' (ab répété)
re.search(r"ab+", "ababab")       # Match ! 'ab' seulement (b répété)

# Capturer pour extraire
match = re.search(r"(\d+)-(\d+)-(\d+)", "Date: 25-12-2024")
if match:
    print(match.group(0))  # '25-12-2024' (tout le match)
    print(match.group(1))  # '25' (premier groupe)
    print(match.group(2))  # '12' (deuxième groupe)
    print(match.group(3))  # '2024' (troisième groupe)

Groupes nommés (plus lisible) :

pattern = r"(?P<jour>\d+)-(?P<mois>\d+)-(?P<annee>\d+)"
match = re.search(pattern, "Date: 25-12-2024")
if match:
    print(match.group("jour"))   # '25'
    print(match.group("mois"))   # '12'
    print(match.group("annee"))  # '2024'

Groupes non-capturants :

Parfois, vous voulez grouper sans capturer. Utilisez (?:...).

# Avec capture (groupe 1 = "ab")
re.search(r"(ab)+", "ababab").groups()   # ('ab',)

# Sans capture (pas de groupe)
re.search(r"(?:ab)+", "ababab").groups() # ()

Partie 3 : Les fonctions du module re

re.search() : Trouver la première occurrence

import re

texte = "Mon email est contact@example.com et aussi info@test.fr"

# Trouve la PREMIÈRE occurrence
match = re.search(r"\w+@\w+\.\w+", texte)
if match:
    print(match.group())  # 'contact@example.com'

re.match() : Matcher au début seulement

# match() cherche seulement au DÉBUT de la chaîne
re.match(r"\d+", "123abc")    # Match ! '123'
re.match(r"\d+", "abc123")    # None (pas au début)

# Équivalent à search avec ^
re.search(r"^\d+", "abc123")  # None

re.findall() : Trouver toutes les occurrences

texte = "Mon email est contact@example.com et aussi info@test.fr"

# Trouve TOUTES les occurrences
emails = re.findall(r"\w+@\w+\.\w+", texte)
print(emails)  # ['contact@example.com', 'info@test.fr']

# Avec des groupes, retourne les groupes
dates = re.findall(r"(\d+)/(\d+)/(\d+)", "Dates: 25/12/2024 et 01/01/2025")
print(dates)  # [('25', '12', '2024'), ('01', '01', '2025')]

re.finditer() : Itérer sur les matchs

texte = "Scores: 10, 25, 42, 100"

# Itère sur chaque match (plus d'infos que findall)
for match in re.finditer(r"\d+", texte):
    print(f"Trouvé '{match.group()}' à la position {match.start()}-{match.end()}")

# Trouvé '10' à la position 8-10
# Trouvé '25' à la position 12-14
# Trouvé '42' à la position 16-18
# Trouvé '100' à la position 20-23

re.sub() : Remplacer

texte = "Mon numéro est 06-12-34-56-78"

# Remplacer les tirets par des espaces
nouveau = re.sub(r"-", " ", texte)
print(nouveau)  # 'Mon numéro est 06 12 34 56 78'

# Masquer les chiffres
masque = re.sub(r"\d", "X", texte)
print(masque)  # 'Mon numéro est XX-XX-XX-XX-XX'

# Utiliser les groupes dans le remplacement
texte = "Bonjour Jean, Bonjour Marie"
nouveau = re.sub(r"Bonjour (\w+)", r"Salut \1", texte)
print(nouveau)  # 'Salut Jean, Salut Marie'

# Avec une fonction
def majuscule(match):
    return match.group().upper()

texte = "hello world"
nouveau = re.sub(r"\b\w", majuscule, texte)
print(nouveau)  # 'Hello World'

re.split() : Découper

texte = "pomme,orange;banane kiwi"

# Découper sur virgule, point-virgule OU espace
fruits = re.split(r"[,;\s]+", texte)
print(fruits)  # ['pomme', 'orange', 'banane', 'kiwi']

# Garder les séparateurs
parties = re.split(r"(\d+)", "abc123def456")
print(parties)  # ['abc', '123', 'def', '456', '']

re.compile() : Compiler une regex

Si vous utilisez la même regex plusieurs fois, compilez-la pour de meilleures performances.

# Sans compilation (OK pour usage unique)
re.search(r"\d+", texte1)
re.search(r"\d+", texte2)
re.search(r"\d+", texte3)

# Avec compilation (meilleur pour usage répété)
pattern = re.compile(r"\d+")
pattern.search(texte1)
pattern.search(texte2)
pattern.search(texte3)
# Exemple complet
import re

email_pattern = re.compile(r"[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+")

emails_a_verifier = [
    "contact@example.com",
    "pas un email",
    "test@test.fr",
    "invalide@",
]

for email in emails_a_verifier:
    if email_pattern.fullmatch(email):
        print(f"✓ {email} est valide")
    else:
        print(f"✗ {email} est invalide")

Les flags (options)

Les flags modifient le comportement de la regex.

# re.IGNORECASE (ou re.I) : Ignore la casse
re.search(r"python", "PYTHON", re.IGNORECASE)  # Match !
re.search(r"python", "PYTHON", re.I)           # Pareil

# re.MULTILINE (ou re.M) : ^ et $ matchent chaque ligne
texte = """Ligne 1
Ligne 2
Ligne 3"""
re.findall(r"^Ligne", texte)                    # ['Ligne'] (seulement la 1ère)
re.findall(r"^Ligne", texte, re.MULTILINE)      # ['Ligne', 'Ligne', 'Ligne']

# re.DOTALL (ou re.S) : Le point matche aussi \n
texte = "Hello\nWorld"
re.search(r"Hello.World", texte)                # None
re.search(r"Hello.World", texte, re.DOTALL)     # Match !

# re.VERBOSE (ou re.X) : Regex sur plusieurs lignes avec commentaires
pattern = re.compile(r"""
    ^                   # Début de chaîne
    [a-zA-Z0-9_.+-]+    # Partie locale de l'email
    @                   # Arobase
    [a-zA-Z0-9-]+       # Domaine
    \.                  # Point
    [a-zA-Z0-9-.]+      # Extension
    $                   # Fin de chaîne
""", re.VERBOSE)

# Combiner plusieurs flags
re.search(r"hello", "HELLO\nWORLD", re.IGNORECASE | re.MULTILINE)

Partie 4 : Exemples pratiques

Valider une adresse email

import re

def valider_email(email):
    """Vérifie si une adresse email est valide."""
    pattern = r"^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$"
    return bool(re.match(pattern, email))

# Tests
emails = [
    "contact@example.com",      # Valide
    "user.name@domain.fr",      # Valide
    "test@sub.domain.org",      # Valide
    "invalid@",                 # Invalide
    "@nodomain.com",            # Invalide
    "spaces not@allowed.com",   # Invalide
]

for email in emails:
    status = "✓" if valider_email(email) else "✗"
    print(f"{status} {email}")

Valider un numéro de téléphone français

import re

def valider_telephone_fr(numero):
    """Vérifie si un numéro de téléphone français est valide."""
    # Accepte : 0612345678, 06 12 34 56 78, 06-12-34-56-78, +33612345678
    pattern = r"^(?:(?:\+33|0)\s?[1-9])(?:[\s.-]?\d{2}){4}$"
    return bool(re.match(pattern, numero))

# Normaliser un numéro
def normaliser_telephone(numero):
    """Convertit un numéro au format 0612345678."""
    # Enlever tous les caractères non numériques sauf +
    numero = re.sub(r"[^\d+]", "", numero)
    # Remplacer +33 par 0
    numero = re.sub(r"^\+33", "0", numero)
    return numero

# Tests
numeros = [
    "06 12 34 56 78",
    "0612345678",
    "+33 6 12 34 56 78",
    "06-12-34-56-78",
    "123",  # Trop court
]

for num in numeros:
    if valider_telephone_fr(num):
        print(f"✓ {num}{normaliser_telephone(num)}")
    else:
        print(f"✗ {num}")

Extraire des URLs d'un texte

import re

def extraire_urls(texte):
    """Extrait toutes les URLs d'un texte."""
    pattern = r"https?://[^\s<>\"']+"
    return re.findall(pattern, texte)

# Test
texte = """
Visitez notre site https://example.com pour plus d'infos.
Documentation : https://docs.python.org/3/library/re.html
Contact : http://contact.example.fr/form?id=123
"""

urls = extraire_urls(texte)
for url in urls:
    print(f"URL trouvée : {url}")

Valider un mot de passe fort

import re

def valider_mot_de_passe(mdp):
    """
    Vérifie qu'un mot de passe est fort :

    - Au moins 8 caractères

    - Au moins une majuscule

    - Au moins une minuscule

    - Au moins un chiffre

    - Au moins un caractère spécial
    """
    if len(mdp) < 8:
        return False, "Au moins 8 caractères requis"

    if not re.search(r"[A-Z]", mdp):
        return False, "Au moins une majuscule requise"

    if not re.search(r"[a-z]", mdp):
        return False, "Au moins une minuscule requise"

    if not re.search(r"\d", mdp):
        return False, "Au moins un chiffre requis"

    if not re.search(r"[!@#$%^&*(),.?\":{}|<>]", mdp):
        return False, "Au moins un caractère spécial requis"

    return True, "Mot de passe valide"

# Tests
mots_de_passe = [
    "abc",              # Trop court
    "abcdefgh",         # Pas de majuscule
    "Abcdefgh",         # Pas de chiffre
    "Abcdefg1",         # Pas de caractère spécial
    "Abcdef1!",         # Valide !
]

for mdp in mots_de_passe:
    valide, message = valider_mot_de_passe(mdp)
    status = "✓" if valide else "✗"
    print(f"{status} '{mdp}' : {message}")

Extraire des données structurées

import re

def parser_log_apache(ligne):
    """Parse une ligne de log Apache."""
    pattern = r'(?P<ip>\d+\.\d+\.\d+\.\d+).*\[(?P<date>[^\]]+)\].*"(?P<methode>\w+) (?P<url>[^\s]+).*" (?P<status>\d+)'

    match = re.search(pattern, ligne)
    if match:
        return match.groupdict()
    return None

# Exemple
log = '192.168.1.1 - - [25/Dec/2024:10:15:30 +0000] "GET /index.html HTTP/1.1" 200 1234'

resultat = parser_log_apache(log)
if resultat:
    print(f"IP: {resultat['ip']}")
    print(f"Date: {resultat['date']}")
    print(f"Méthode: {resultat['methode']}")
    print(f"URL: {resultat['url']}")
    print(f"Status: {resultat['status']}")

Nettoyer du texte

import re

def nettoyer_texte(texte):
    """Nettoie un texte : espaces multiples, caractères spéciaux, etc."""

    # Remplacer les espaces multiples par un seul espace
    texte = re.sub(r"\s+", " ", texte)

    # Supprimer les espaces en début et fin
    texte = texte.strip()

    # Supprimer les caractères non-alphanumériques (sauf espaces et ponctuation basique)
    texte = re.sub(r"[^\w\s.,!?-]", "", texte)

    return texte

# Test
texte_sale = "   Bonjour    le   monde!!!   @#$%   Comment    ça va?   "
print(f"Avant : '{texte_sale}'")
print(f"Après : '{nettoyer_texte(texte_sale)}'")

Formater des montants

import re

def formater_montant(texte):
    """Ajoute le symbole € aux montants et formate avec 2 décimales."""

    def formatter(match):
        montant = float(match.group())
        return f"{montant:.2f} €"

    # Matcher les nombres (entiers ou décimaux)
    return re.sub(r"\d+(?:\.\d+)?", formatter, texte)

# Test
texte = "Le produit coûte 19.99 et la livraison 5"
print(formater_montant(texte))
# "Le produit coûte 19.99 € et la livraison 5.00 €"

Extraire des hashtags et mentions

import re

def extraire_hashtags_mentions(texte):
    """Extrait les hashtags et mentions d'un texte (style Twitter/X)."""
    hashtags = re.findall(r"#(\w+)", texte)
    mentions = re.findall(r"@(\w+)", texte)
    return {"hashtags": hashtags, "mentions": mentions}

# Test
tweet = "Super article sur #Python et #Regex ! Merci @codewithmpia pour le partage 🚀"
resultat = extraire_hashtags_mentions(tweet)
print(f"Hashtags : {resultat['hashtags']}")    # ['Python', 'Regex']
print(f"Mentions : {resultat['mentions']}")    # ['codewithmpia']

Partie 5 : Les pièges à éviter

Piège 1 : Oublier le r (raw string)

import re

# MAUVAIS : \b est interprété comme backspace
re.search("\bcat\b", "cat")   # Ne marche pas !

# BON : r"..." préserve les backslashes
re.search(r"\bcat\b", "cat")  # Match !

Piège 2 : Les quantificateurs gourmands (greedy)

Par défaut, *, +, ? sont gourmands : ils matchent le plus possible.

import re

html = "<div>Contenu 1</div><div>Contenu 2</div>"

# MAUVAIS : Matche tout de <div> à </div> (le dernier !)
match = re.search(r"<div>.*</div>", html)
print(match.group())  # '<div>Contenu 1</div><div>Contenu 2</div>'

# BON : Utiliser le quantificateur non-gourmand (lazy) avec ?
match = re.search(r"<div>.*?</div>", html)
print(match.group())  # '<div>Contenu 1</div>'

Quantificateurs non-gourmands :

  • *? : Zéro ou plus (le moins possible)

  • +? : Un ou plus (le moins possible)

  • ?? : Zéro ou un (le moins possible)

  • {n,m}? : Entre n et m (le moins possible)

Piège 3 : Échapper les caractères spéciaux

Si vous cherchez un caractère spécial littéralement, échappez-le avec \.

import re

# MAUVAIS : Le point matche n'importe quel caractère
re.search(r"test.com", "testXcom")  # Match ! (pas voulu)

# BON : Échapper le point
re.search(r"test\.com", "testXcom")  # None
re.search(r"test\.com", "test.com")  # Match !

# Pour échapper automatiquement une chaîne
texte = "Prix: 19.99$"
pattern = re.escape(texte)  # 'Prix:\\ 19\\.99\\$'
import re

texte = "Bonjour Python"

# match() cherche SEULEMENT au début
re.match(r"Python", texte)   # None

# search() cherche PARTOUT
re.search(r"Python", texte)  # Match !

Piège 5 : Les groupes et findall()

import re

texte = "12-34 56-78"

# Sans groupes : retourne les matchs complets
re.findall(r"\d+-\d+", texte)     # ['12-34', '56-78']

# Avec groupes : retourne SEULEMENT les groupes !
re.findall(r"(\d+)-(\d+)", texte) # [('12', '34'), ('56', '78')]

# Pour avoir les matchs complets AVEC des groupes
re.findall(r"(\d+-\d+)", texte)   # ['12-34', '56-78']

Piège 6 : Les performances (backtracking catastrophique)

Certaines regex peuvent être très lentes sur certains textes.

import re
import time

# MAUVAIS : Peut être très lent avec certaines entrées
pattern_lent = r"(a+)+"

# BON : Éviter les quantificateurs imbriqués
pattern_rapide = r"a+"

# Test de performance
texte = "a" * 30 + "b"

start = time.time()
re.search(pattern_rapide, texte)
print(f"Rapide : {time.time() - start:.4f}s")

# Le pattern lent pourrait prendre des secondes voire des minutes !

Règle d'or : Évitez les quantificateurs imbriqués comme (a+)+, (a*)*, etc.

Partie 6 : Bonnes pratiques

1. Commentez vos regex complexes

import re

# MAUVAIS : Qu'est-ce que ça fait ?
pattern = r"^(?:\+33|0)[1-9](?:[\s.-]?\d{2}){4}$"

# BON : Utilisez re.VERBOSE pour commenter
pattern = re.compile(r"""
    ^                       # Début de chaîne
    (?:\+33|0)              # Indicatif (+33 ou 0)
    [1-9]                   # Premier chiffre (pas 0)
    (?:[\s.-]?\d{2}){4}     # 4 groupes de 2 chiffres (avec séparateurs optionnels)
    $                       # Fin de chaîne
""", re.VERBOSE)

2. Testez vos regex progressivement

import re

# Construisez étape par étape
texte = "email: contact@example.com"

# Étape 1 : Trouver quelque chose
re.search(r"\w+", texte)

# Étape 2 : Ajouter le @
re.search(r"\w+@", texte)

# Étape 3 : Ajouter le domaine
re.search(r"\w+@\w+", texte)

# Étape 4 : Ajouter le point et l'extension
re.search(r"\w+@\w+\.\w+", texte)

# Étape 5 : Affiner si nécessaire
re.search(r"[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+", texte)

3. Utilisez des outils de test

Sites web pour tester vos regex :

  • regex101.com : Excellent, avec explications détaillées

  • pythex.org : Spécifique à Python

  • regexr.com : Interface intuitive

4. Préférez la clarté à la concision

# MAUVAIS : Regex cryptique
r"^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$"

# BON : Plusieurs vérifications séparées (plus lisible, plus maintenable)
def valider_mdp(mdp):
    if len(mdp) < 8:
        return False
    if not re.search(r"[a-z]", mdp):
        return False
    if not re.search(r"[A-Z]", mdp):
        return False
    if not re.search(r"\d", mdp):
        return False
    if not re.search(r"[@$!%*?&]", mdp):
        return False
    return True

5. Compilez les regex réutilisées

import re

# Pour une utilisation unique : OK
re.search(r"\d+", texte)

# Pour une utilisation répétée : compilez !
PATTERN_NOMBRE = re.compile(r"\d+")

for ligne in fichier:
    match = PATTERN_NOMBRE.search(ligne)

6. Gérez les erreurs

import re

def rechercher_pattern(pattern, texte):
    """Recherche un pattern en gérant les erreurs de syntaxe."""
    try:
        return re.search(pattern, texte)
    except re.error as e:
        print(f"Erreur de regex : {e}")
        return None

# Pattern invalide
rechercher_pattern(r"[invalid", "texte")  # Affiche l'erreur proprement

Cheat Sheet : Aide-mémoire Regex

Caractères spéciaux

Caractère Signification
. N'importe quel caractère (sauf \n)
^ Début de chaîne
$ Fin de chaîne
\ Échappement
\| OU (alternation)

Quantificateurs

Quantificateur Signification
* 0 ou plus (gourmand)
+ 1 ou plus (gourmand)
? 0 ou 1 (gourmand)
{n} Exactement n fois
{n,} Au moins n fois
{n,m} Entre n et m fois
*?, +?, ?? Versions non-gourmandes

Classes de caractères

Classe Signification
[abc] a, b ou c
[^abc] Tout sauf a, b, c
[a-z] Lettres minuscules
[A-Z] Lettres majuscules
[0-9] Chiffres
[a-zA-Z0-9] Alphanumériques

Séquences spéciales

Séquence Signification
\d Chiffre [0-9]
\D Non-chiffre
\w Alphanumérique [a-zA-Z0-9_]
\W Non-alphanumérique
\s Espace blanc
\S Non-espace
\b Limite de mot
\B Non-limite de mot

Groupes

Syntaxe Signification
(...) Groupe capturant
(?:...) Groupe non-capturant
(?P<nom>...) Groupe nommé
\1, \2 Références arrière

Flags Python

Flag Signification
re.IGNORECASE ou re.I Ignore la casse
re.MULTILINE ou re.M ^ et $ par ligne
re.DOTALL ou re.S . matche \n
re.VERBOSE ou re.X Mode commenté

Fonctions principales

re.search(pattern, texte)      # Première occurrence
re.match(pattern, texte)       # Au début seulement
re.findall(pattern, texte)     # Toutes les occurrences (liste)
re.finditer(pattern, texte)    # Toutes les occurrences (itérateur)
re.sub(pattern, repl, texte)   # Remplacer
re.split(pattern, texte)       # Découper
re.compile(pattern)            # Compiler

Conclusion

Félicitations ! Vous connaissez maintenant les regex en Python.

Ce qu'on a couvert :

  • Les bases : caractères, quantificateurs, classes

  • Le module re et ses fonctions

  • Des exemples pratiques pour le quotidien

  • Les pièges classiques à éviter

  • Les bonnes pratiques pour écrire des regex maintenables

Les commandements du Regex-fu :

  1. Toujours utiliser r"..." (raw strings)

  2. Tester progressivement, étape par étape

  3. Utiliser regex101.com pour débugger

  4. Préférer plusieurs regex simples à une regex complexe

  5. Commenter les regex complexes avec re.VERBOSE

  6. Attention aux quantificateurs gourmands

  7. Compiler les regex réutilisées

  8. Échapper les caractères spéciaux avec \

  9. Ne pas oublier les cas limites

  10. La pratique rend parfait !

Rappelez-vous :

  • Les regex semblent cryptiques au début, c'est normal

  • Personne ne mémorise toutes les syntaxes (on cherche tous !)

  • Commencez simple et complexifiez progressivement

  • Un regex101.com ouvert dans un onglet est votre meilleur ami

Prochaines étapes :

  1. Pratiquez sur regex101.com avec vos propres exemples

  2. Essayez d'extraire des données d'un fichier texte

  3. Créez une fonction de validation pour votre projet

  4. Explorez les lookahead et lookbehind (niveau avancé)

  5. Pratiquez, pratiquez, pratiquez !

Les regex, c'est comme les échecs : facile à apprendre, difficile à maîtriser. Mais une fois que vous les maîtrisez, c'est un super pouvoir que vous utiliserez tous les jours.

Vous avez des questions sur les regex ? Un pattern qui vous résiste ? Partagez en commentaire ! Et si ce guide vous a aidé, partagez-le avec d'autres devs qui veulent enfin comprendre les expressions régulières.

Commentaires (0)

Laisser un commentaire

Aucun commentaire pour le moment. Soyez le premier à commenter !