Aller au contenu

Expressions régulières

Mise à jour :

logo python

Les expressions régulières, ou regex, c’est un peu comme une langue secrète pour communiquer avec vos données textuelles. Si vous vous êtes déjà demandé comment extraire des adresses e-mail d’un document, vérifier un numéro de téléphone ou remplacer des mots spécifiques dans un texte, les regex sont là pour vous simplifier la vie.

Avec Python, manipuler les regex est un jeu d’enfant grâce au module intégré re. Que vous soyez développeur débutant ou expérimenté, apprendre à utiliser les regex vous ouvrira de nouvelles perspectives pour traiter des chaînes de caractères de manière rapide et efficace.

Mais pas de panique, je sais que les regex peuvent sembler un peu intimidantes au départ. Entre les astérisques, les parenthèses, et les mystérieuses séquences comme \d ou \w, on peut vite se sentir perdu. Dans ce guide, je vais vous accompagner étape par étape, avec des explications claires et des exemples concrets. Vous verrez, c’est beaucoup plus simple qu’il n’y paraît !

Prêt à plonger dans l’univers fascinant des regex en Python ? Alors, allons-y !

Premier pas

Bonne nouvelle : vous n’avez rien à installer pour utiliser les expressions régulières en Python ! Le module re est intégré par défaut dans la bibliothèque standard de Python. En gros, il est prêt à l’emploi dès que vous installez Python.

Avant toute chose, on importe simplement le module re dans notre script. Voici comment faire :

import re

Et voilà, vous êtes prêt à travailler avec des regex ! Maintenant, passons à l’essentiel : écrire et tester des motifs.

Une regex, c’est un peu comme un détective textuel. Par exemple, si vous voulez trouver le mot “Python” dans une phrase, vous pouvez utiliser cette expression régulière :

import re
# La chaîne de texte où chercher
texte = "J'apprends Python avec passion."
# Rechercher le mot "Python"
resultat = re.search("Python", texte)
if resultat:
print("Mot trouvé !")
else:
print("Mot non trouvé.")

Quand vous exécutez ce script, il affichera “Mot trouvé !” si la chaîne contient “Python”. Facile, non ?

Si vous voulez que votre recherche ignore les majuscules et minuscules, ajoutez l’option re.IGNORECASE :

resultat = re.search("python", texte, re.IGNORECASE)

Les bases des regex

Pour vraiment comprendre les expressions régulières, il faut se familiariser avec les bases. Les regex utilisent des caractères spéciaux et des règles qui permettent de rechercher, capturer ou manipuler du texte. Pas d’inquiétude, je vais tout vous expliquer simplement !

Les regex reposent sur des symboles qui ont des significations précises. Voici les principaux que vous rencontrerez souvent :

  1. Le point (.) Correspond à n’importe quel caractère sauf une nouvelle ligne (\n). Exemple :

    import re
    texte = "chat"
    print(re.search("c.a.", texte)) # Renvoie None car "chat" ne correspond pas à "c.a."
  2. Le symbole d’ancrage début (^) Vérifie si un motif est au début de la chaîne. Exemple :

    texte = "Python est génial"
    print(re.match("^Python", texte)) # Motif trouvé au début
  3. Le symbole d’ancrage fin ($) Vérifie si un motif est à la fin de la chaîne. Exemple :

    texte = "J'adore le Python"
    print(re.search("Python$", texte)) # Motif trouvé à la fin
  4. Les crochets ([]) Spécifient un ensemble de caractères possibles. Exemple :

    texte = "chat"
    print(re.search("[aeiou]", texte)) # Trouve "a", une voyelle
  5. Le tiret dans les crochets ([a-z]) Définit une plage de caractères. Exemple :

    texte = "Mon mot de passe est sûr123"
    print(re.search("[0-9]", texte)) # Trouve un chiffre
  6. L’étoile (*) Correspond à zéro ou plusieurs occurrences du caractère précédent. Exemple :

    texte = "baaa"
    print(re.search("ba*", texte)) # Trouve "baaa"
  7. Le plus (+) Correspond à une ou plusieurs occurrences du caractère précédent. Exemple :

    texte = "baaa"
    print(re.search("ba+", texte)) # Trouve aussi "baaa"
  8. Le point d’interrogation (?) Correspond à zéro ou une occurrence du caractère précédent. Exemple :

    texte = "color"
    print(re.search("colou?r", texte)) # Trouve "color" ou "colour"

Classes de caractères et métasymboles

Les classes de caractères et les métasymboles permettent de créer des expressions régulières plus flexibles et précises. Ils définissent des ensembles de caractères ou des motifs spécifiques que vous pouvez utiliser dans vos recherches.

Les classes de caractères

Les classes de caractères permettent de définir un ensemble de caractères à matcher. Elles sont encadrées par des crochets [].

  1. Caractères individuels Correspondent à l’un des caractères définis dans les crochets. Exemple :

    import re
    texte = "chat"
    motif = r"[abc]"
    resultat = re.search(motif, texte)
    print(resultat.group()) # Trouve "c"
  2. Plages de caractères Utilisez un tiret - pour définir une plage. Exemple :

    import re
    texte = "abcd"
    motif = r"[a-c]"
    resultat = re.findall(motif, texte)
    print(resultat) # ['a', 'b', 'c']
  3. Exclusion avec ^ Le ^ en début de crochets exclut les caractères spécifiés. Exemple :

    import re
    texte = "123abc"
    motif = r"[^0-9]"
    resultat = re.findall(motif, texte)
    print(resultat) # ['a', 'b', 'c']
  4. Combinaison de caractères et plages Vous pouvez combiner des plages et des caractères individuels. Exemple :

    import re
    texte = "a1b2c3"
    motif = r"[a-z1-3]"
    resultat = re.findall(motif, texte)
    print(resultat) # ['a', '1', 'b', '2', 'c', '3']

Les métasymboles

Les métasymboles représentent des motifs spécifiques.

  1. Le point (.) Correspond à n’importe quel caractère sauf une nouvelle ligne. Exemple :

    import re
    texte = "abc\ndef"
    motif = r"a.c"
    resultat = re.search(motif, texte)
    print(resultat.group()) # "abc"
  2. Le backslash (\) Utilisé pour échapper un caractère spécial ou pour indiquer une classe prédéfinie. Exemple :

    import re
    texte = "Le coût est de 100$"
    motif = r"100\$"
    resultat = re.search(motif, texte)
    print(resultat.group()) # "100$"
  3. Le pipe (|) Correspond à une alternative (ou logique). Exemple :

    import re
    texte = "J'aime les pommes ou les oranges"
    motif = r"pommes|oranges"
    resultat = re.search(motif, texte)
    print(resultat.group()) # "pommes"

Classes de caractères prédéfinies

Ces classes simplifient les recherches courantes.

  1. \d Correspond à un chiffre (0-9). Exemple :

    import re
    texte = "Il y a 42 pommes"
    motif = r"\d+"
    resultat = re.search(motif, texte)
    print(resultat.group()) # "42"
  2. \D Correspond à tout sauf un chiffre. Exemple :

    import re
    texte = "42 pommes"
    motif = r"\D+"
    resultat = re.search(motif, texte)
    print(resultat.group()) # " pommes"
  3. \w Correspond à un caractère alphanumérique (a-z, A-Z, 0-9, et _). Exemple :

    import re
    texte = "Python_3 est génial !"
    motif = r"\w+"
    resultat = re.findall(motif, texte)
    print(resultat) # ['Python_3', 'est', 'génial']
  4. \W Correspond à tout sauf un caractère alphanumérique. Exemple :

    import re
    texte = "Python_3 est génial !"
    motif = r"\W+"
    resultat = re.findall(motif, texte)
    print(resultat) # [' ', ' ', ' !']
  5. \s Correspond à un espace, une tabulation ou une nouvelle ligne. Exemple :

    import re
    texte = "Python est génial"
    motif = r"\s"
    resultat = re.findall(motif, texte)
    print(resultat) # [' ', ' ']
  6. \S Correspond à tout sauf un espace. Exemple :

    import re
    texte = "Python est génial"
    motif = r"\S+"
    resultat = re.findall(motif, texte)
    print(resultat) # ['Python', 'est', 'génial']

Les quantificateurs

Les quantificateurs sont des outils puissants des expressions régulières qui permettent de définir combien de fois un motif peut se répéter. Ils sont essentiels pour matcher des motifs variables, comme des séquences de chiffres ou des mots avec des longueurs différentes.

Les principaux quantificateurs

  1. L’astérisque (*) Correspond à zéro ou plusieurs occurrences du caractère ou du groupe précédent. Exemple :

    import re
    texte = "hellooo"
    motif = r"lo*"
    resultat = re.search(motif, texte)
    print(resultat.group()) # "loo"

    Ici, le motif capture “l” suivi de zéro ou plusieurs “o”.

  2. Le plus (+) Correspond à une ou plusieurs occurrences du caractère ou du groupe précédent. Exemple :

    import re
    texte = "hellooo"
    motif = r"lo+"
    resultat = re.search(motif, texte)
    print(resultat.group()) # "looo"

    Contrairement à *, le motif échoue si aucune occurrence n’est trouvée.

  3. Le point d’interrogation (?) Correspond à zéro ou une occurrence du caractère ou du groupe précédent. Exemple :

    import re
    texte = "color" # ou "colour"
    motif = r"colou?r"
    resultat = re.search(motif, texte)
    print(resultat.group()) # "color" ou "colour"
  4. Les accolades ({n} ou {n,m}) Correspondent à un nombre précis ou une plage d’occurrences.

    • {n} : exactement n occurrences.
    • {n,} : au moins n occurrences.
    • {n,m} : entre n et m occurrences.

    Exemple :

    import re
    texte = "aaaaa"
    motif = r"a{2,4}"
    resultat = re.search(motif, texte)
    print(resultat.group()) # "aaaa"

Quantificateurs “gourmands” et “non-gourmands”

Par défaut, les quantificateurs sont gourmands, c’est-à-dire qu’ils capturent autant de caractères que possible. Pour les rendre non-gourmands, ajoutez un point d’interrogation ? juste après le quantificateur.

Exemple :

import re
texte = "<tag>contenu</tag>"
motif_gourmand = r"<.*>"
motif_non_gourmand = r"<.*?>"
resultat_gourmand = re.search(motif_gourmand, texte)
resultat_non_gourmand = re.search(motif_non_gourmand, texte)
print("Gourmand :", resultat_gourmand.group()) # "<tag>contenu</tag>"
print("Non-gourmand :", resultat_non_gourmand.group()) # "<tag>"

Combinaisons pratiques

  1. Capturer une adresse IP : Une adresse IP se compose de 4 groupes de 1 à 3 chiffres séparés par des points.

    import re
    texte = "Mon IP est 192.168.1.1"
    motif = r"(\d{1,3}\.){3}\d{1,3}"
    resultat = re.search(motif, texte)
    if resultat:
    print("IP trouvée :", resultat.group())
  2. Trouver des mots répétés :

    import re
    texte = "Je suis très très content."
    motif = r"\b(\w+)\s+\1\b"
    resultat = re.search(motif, texte)
    if resultat:
    print("Mot répété trouvé :", resultat.group())
  3. Valider un numéro de téléphone :

    import re
    texte = "Mon numéro est 06-12-34-56-78"
    motif = r"\d{2}(-\d{2}){4}"
    resultat = re.search(motif, texte)
    if resultat:
    print("Numéro trouvé :", resultat.group())

Les fonctions du module re

Le module re de Python propose plusieurs fonctions très pratiques pour travailler avec les expressions régulières. Chaque fonction a un rôle précis et vous permet de rechercher, remplacer ou diviser des chaînes de caractères efficacement.

Fonction re.match()

La fonction re.match() vérifie si un motif apparaît au début d’une chaîne. Si ce n’est pas le cas, elle retourne None.

Exemple simple :

import re
texte = "Python est génial"
motif = r"Python"
resultat = re.match(motif, texte)
if resultat:
print("Match trouvé :", resultat.group())
else:
print("Aucun match trouvé")

Limitation : Si le motif n’est pas au début de la chaîne, il ne sera pas trouvé.

Fonction re.search()

Contrairement à re.match(), la fonction re.search() recherche le motif n’importe où dans la chaîne.

Exemple :

import re
texte = "J'adore le Python"
motif = r"Python"
resultat = re.search(motif, texte)
if resultat:
print("Match trouvé :", resultat.group())
else:
print("Aucun match trouvé")

Ici, le mot “Python” est trouvé même s’il n’est pas au début de la chaîne.

Fonction re.findall()

La fonction re.findall() retourne une liste contenant toutes les occurrences correspondant au motif.

Exemple :

import re
texte = "123 456 789"
motif = r"\d+"
resultat = re.findall(motif, texte)
print("Occurrences trouvées :", resultat)

Sortie :

Occurrences trouvées : ['123', '456', '789']

Fonction re.finditer()

C’est une variante de re.findall(), mais elle retourne un itérateur au lieu d’une liste. Cet itérateur contient des objets match que vous pouvez manipuler.

Exemple :

import re
texte = "Bonjour Python, au revoir Python"
motif = r"Python"
resultats = re.finditer(motif, texte)
for match in resultats:
print("Match trouvé à la position :", match.start(), "-", match.end())

Fonction re.sub()

La fonction re.sub() permet de remplacer un motif par une autre chaîne.

Exemple :

import re
texte = "Python est génial, Python est puissant"
motif = r"Python"
remplacement = "Java"
resultat = re.sub(motif, remplacement, texte)
print(resultat)

Sortie :

Java est génial, Java est puissant

Fonction re.split()

La fonction re.split() découpe une chaîne en fonction d’un motif et retourne une liste des segments.

Exemple :

import re
texte = "Un;deux;trois;quatre"
motif = r";"
resultat = re.split(motif, texte)
print(resultat)

Sortie :

['Un', 'deux', 'trois', 'quatre']

Fonction re.compile()

Vous pouvez “préparer” une regex pour la réutiliser plusieurs fois grâce à re.compile(). Cela peut aussi améliorer les performances.

Exemple :

import re
texte = "Python est génial. Python est puissant."
motif = re.compile(r"Python")
resultats = motif.findall(texte)
print("Occurrences trouvées :", resultats)

Travailler avec des groupes et des captures

Les groupes et les captures sont l’un des aspects les plus puissants des expressions régulières en Python. Ils permettent d’extraire des sous-parties précises d’un texte, comme un e-mail dans une phrase ou une date dans un journal.

Qu’est-ce qu’un groupe ?

Un groupe est une partie de l’expression régulière entourée de parenthèses (). Ces parenthèses permettent de capturer et de manipuler des sous-chaînes correspondant au motif.

Exemple simple :

import re
texte = "Mon numéro est 06-12-34-56-78"
motif = r"(\d{2})-(\d{2})-(\d{2})-(\d{2})-(\d{2})"
resultat = re.search(motif, texte)
if resultat:
print("Match complet :", resultat.group()) # Match complet
print("Groupe 1 :", resultat.group(1)) # Premier groupe
print("Groupe 2 :", resultat.group(2)) # Deuxième groupe

Sortie :

Match complet : 06-12-34-56-78
Groupe 1 : 06
Groupe 2 : 12

Numérotation des groupes

Les groupes capturés sont numérotés automatiquement de gauche à droite, à partir de 1 (le groupe 0 correspond au motif complet).

Exemple avec plusieurs groupes :

import re
texte = "Date : 2024-12-01"
motif = r"(\d{4})-(\d{2})-(\d{2})"
resultat = re.search(motif, texte)
if resultat:
print("Année :", resultat.group(1)) # 2024
print("Mois :", resultat.group(2)) # 12
print("Jour :", resultat.group(3)) # 01

Nommage des groupes

Pour rendre votre regex plus lisible, vous pouvez nommer vos groupes avec (?P<nom>). Vous accéderez ensuite aux groupes avec leurs noms.

Exemple :

import re
texte = "Date : 2024-12-01"
motif = r"(?P<annee>\d{4})-(?P<mois>\d{2})-(?P<jour>\d{2})"
resultat = re.search(motif, texte)
if resultat:
print("Année :", resultat.group("annee")) # 2024
print("Mois :", resultat.group("mois")) # 12
print("Jour :", resultat.group("jour")) # 01

Récupérer tous les groupes

Vous pouvez récupérer tous les groupes d’un match sous forme de tuple avec groups().

Exemple :

import re
texte = "Date : 2024-12-01"
motif = r"(\d{4})-(\d{2})-(\d{2})"
resultat = re.search(motif, texte)
if resultat:
print("Tous les groupes :", resultat.groups()) # ('2024', '12', '01')

Groupes non capturants

Parfois, vous voulez grouper sans capturer, par exemple pour appliquer un quantificateur à un groupe sans l’enregistrer. Utilisez alors (?:...).

Exemple :

import re
texte = "apple banana apple"
motif = r"(?:apple|banana)"
resultats = re.findall(motif, texte)
print("Occurrences trouvées :", resultats) # ['apple', 'banana', 'apple']

Captures imbriquées

Vous pouvez imbriquer des groupes pour capturer des sous-parties plus précises.

Exemple :

import re
texte = "Coordonnées : (06) 12-34-56-78"
motif = r"\((\d{2})\)\s(\d{2})-(\d{2})-(\d{2})-(\d{2})"
resultat = re.search(motif, texte)
if resultat:
print("Numéro complet :", resultat.group()) # Match complet
print("Préfixe :", resultat.group(1)) # 06

Groupes alternatifs

Vous pouvez utiliser | pour spécifier des alternatives au sein d’un groupe.

Exemple :

import re
texte = "J'aime les pommes ou les oranges"
motif = r"(pommes|oranges)"
resultat = re.search(motif, texte)
if resultat:
print("Fruit trouvé :", resultat.group()) # pommes ou oranges

Utilisation pratique

  1. Extraire un e-mail :

    import re
    texte = "Contactez-nous à support@example.com"
    motif = r"([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})"
    resultat = re.search(motif, texte)
    if resultat:
    print("E-mail trouvé :", resultat.group())
  2. Extraire une URL :

    import re
    texte = "Visitez https://www.example.com pour en savoir plus"
    motif = r"https?://[a-zA-Z0-9.-]+"
    resultat = re.search(motif, texte)
    if resultat:
    print("URL trouvée :", resultat.group())

Expressions régulières avancées

Maintenant que vous maîtrisez les bases des expressions régulières, il est temps de découvrir des fonctionnalités avancées qui rendent les regex encore plus puissantes. Dans ce chapitre, nous allons explorer les assertions, les lookarounds, et les regex optimisées.

Assertions : les ancres de position

Les assertions permettent de fixer des conditions sur la position d’un motif sans le capturer.

  1. Mot entier (\b) Correspond à une limite de mot (début ou fin). Exemple :

    import re
    texte = "J'aime Python, pas Pythonesque"
    motif = r"\bPython\b"
    print(re.search(motif, texte)) # Trouve "Python"
  2. Non-mot entier (\B) Correspond à tout sauf une limite de mot. Exemple :

    import re
    texte = "Pythonesque est complexe"
    motif = r"Python\B"
    print(re.search(motif, texte)) # Trouve "Python" dans "Pythonesque"

Lookahead et Lookbehind : les lookarounds

Les lookarounds permettent de vérifier des motifs avant ou après une position sans les capturer.

  1. Lookahead positif ((?=...)) Vérifie qu’un motif suit la position actuelle. Exemple :

    import re
    texte = "Python3 est génial"
    motif = r"Python(?=\d)"
    print(re.search(motif, texte)) # Trouve "Python" suivi d'un chiffre
  2. Lookahead négatif ((?!...)) Vérifie qu’un motif ne suit pas la position actuelle. Exemple :

    import re
    texte = "Python est génial"
    motif = r"Python(?!\d)"
    print(re.search(motif, texte)) # Trouve "Python" non suivi d'un chiffre
  3. Lookbehind positif ((?<=...)) Vérifie qu’un motif précède la position actuelle. Exemple :

    import re
    texte = "J'aime le Python"
    motif = r"(?<=le )Python"
    print(re.search(motif, texte)) # Trouve "Python" précédé de "le"
  4. Lookbehind négatif ((?<!...)) Vérifie qu’un motif ne précède pas la position actuelle. Exemple :

    import re
    texte = "J'aime Python, pas JavaPython"
    motif = r"(?<!Java)Python"
    print(re.search(motif, texte)) # Trouve "Python" non précédé de "Java"

Modifier le comportement des regex

  1. Mode multi-lignes (re.MULTILINE) Le caractère ^ correspond au début de chaque ligne, et $ à la fin de chaque ligne. Exemple :

    import re
    texte = "Python\nJava\nC++"
    motif = r"^Java"
    print(re.search(motif, texte, re.MULTILINE)) # Trouve "Java" en début de ligne
  2. Mode point étendu (re.DOTALL) Le point (.) correspond également aux sauts de ligne (\n). Exemple :

    import re
    texte = "Bonjour.\nComment ça va ?"
    motif = r".*"
    print(re.search(motif, texte, re.DOTALL).group()) # Capture tout, y compris les sauts de ligne
  3. Mode insensible à la casse (re.IGNORECASE) Les correspondances ignorent les majuscules et les minuscules. Exemple :

    import re
    texte = "PYTHON est génial"
    motif = r"python"
    print(re.search(motif, texte, re.IGNORECASE)) # Trouve "PYTHON"

Bonnes pratiques

Les expressions régulières sont puissantes, mais elles peuvent vite devenir un casse-tête si on les utilise mal. Dans ce chapitre, je vais partager avec vous quelques bonnes pratiques pour écrire des regex efficaces, ainsi que les erreurs courantes à éviter.

  1. Privilégiez la simplicité Évitez les regex trop complexes. Une regex simple est plus facile à lire, à maintenir et à déboguer. Exemple :

    Mauvais :

    ([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})

    Mieux :

    \w+@\w+\.\w{2,}
  2. Ajoutez des commentaires Si votre regex devient trop complexe, utilisez le mode verbose (re.VERBOSE) pour ajouter des commentaires. Exemple :

    import re
    motif = re.compile(r"""
    \w+ # Partie avant l'@
    @ # Symbole @
    \w+\.\w+ # Domaine
    """, re.VERBOSE)
  3. Évitez les regex inutiles Parfois, une fonction Python standard est suffisante. Exemple :

    Mauvais :

    import re
    texte = "Python"
    if re.match(r"Python", texte):
    print("Mot trouvé")

    Mieux :

    texte = "Python"
    if "Python" in texte:
    print("Mot trouvé")
  4. Utilisez des outils pour tester vos regex Des plateformes comme Regex101 vous aident à visualiser et tester vos regex.

  5. Échappez les caractères spéciaux Si vous recherchez des caractères spéciaux (comme . ou *), échappez-les avec \. Exemple :

    import re
    texte = "Fichier.log"
    motif = r"\."
    print(re.search(motif, texte)) # Trouve le point littéral

Astuces pour le débogage

  1. Utilisez re.DEBUG pour afficher des informations sur la regex. Exemple :

    import re
    re.compile(r"\d+", re.DEBUG)
  2. Découpez les regex complexes en sous-parties et testez-les indépendamment.

  3. Visualisez les captures avec resultat.groups() ou resultat.groupdict() pour comprendre ce qui est extrait.

Conclusion

Les expressions régulières sont un outil incroyablement puissant pour manipuler et analyser du texte en Python. Que ce soit pour valider des données, rechercher des motifs ou nettoyer des chaînes, elles vous permettent de gagner du temps et d’automatiser des tâches complexes.

Dans ce guide, nous avons exploré les bases, les fonctions du module re, et des techniques avancées comme les lookarounds et les quantificateurs non-gourmands. Avec ces connaissances, vous êtes désormais prêt à résoudre des problèmes réels et à intégrer les regex dans vos projets.

À mon avis, le plus important est de pratiquer et de garder vos regex simples et lisibles. Et n’oubliez pas : des outils comme Regex101 sont vos meilleurs amis pour tester et affiner vos expressions.

Maintenant, à vous de jouer ! 😊