W3docs

Python RegEx

Apprenez les expressions régulières Python : syntaxe, séquences spéciales, groupes, lookaheads, drapeaux et fonctions du module re avec des exemples clairs.

Les expressions régulières (regex) vous permettent de rechercher, d'extraire et de remplacer du texte à partir de motifs flexibles plutôt que de chaînes exactes. Le module re intégré à Python fournit tout ce dont vous avez besoin. Ce chapitre couvre l'ensemble de la boîte à outils regex : syntaxe, séquences spéciales, quantificateurs, groupes, lookahead/lookbehind, drapeaux et toutes les fonctions clés du module re — avec des exemples corrects et exécutables tout au long.

Pourquoi utiliser les expressions régulières ?

Les méthodes de string simples (str.find(), str.replace(), str.split()) fonctionnent bien pour du texte fixe. Les expressions régulières sont particulièrement utiles lorsque le motif varie :

  • Valider qu'une string ressemble à une adresse e-mail ou à un numéro de téléphone.
  • Extraire toutes les dates d'un document, quel que soit le format exact.
  • Supprimer les balises HTML d'une string.
  • Remplacer plusieurs séquences d'espaces différentes par un seul espace.

Lorsque la tâche consiste à décrire une forme plutôt qu'une valeur fixe, utilisez re.

Chaînes brutes (Raw Strings)

Les motifs regex sont presque toujours écrits sous forme de chaînes brutes (r'...'). Les chaînes brutes traitent les barres obliques inverses comme des caractères littéraux, ce qui est important car les regex utilisent de nombreuses séquences avec barre oblique inverse (\d, \w, \s, \b). Sans le préfixe r, vous auriez besoin de doubler les barres obliques inverses partout :

import re

# Both patterns are identical — raw string is easier to read
re.findall(r'\d+', 'abc 123')   # raw:    r'\d+'
re.findall('\\d+', 'abc 123')   # normal: '\\d+'

Utilisez des chaînes brutes pour chaque motif regex — c'est la convention universelle.

Syntaxe de base : métacaractères

Les métacaractères sont des caractères ayant une signification spéciale à l'intérieur d'un motif. Les caractères littéraux se correspondent exactement à eux-mêmes.

MétacaractèreSignification
.N'importe quel caractère sauf un saut de ligne
^Début de la string (ou de la ligne en mode MULTILINE)
$Fin de la string (ou de la ligne en mode MULTILINE)
*Zéro ou plusieurs occurrences de l'élément précédent
+Une ou plusieurs occurrences de l'élément précédent
?Zéro ou une occurrence de l'élément précédent
{n}Exactement n répétitions
{n,m}Entre n et m répétitions
[...]Classe de caractères — n'importe quel caractère listé à l'intérieur
[^...]Classe niée — n'importe quel caractère non listé
|Alternation — expression gauche ou droite
()Groupe capturant
\Échapper un métacaractère ou démarrer une séquence spéciale

Pour faire correspondre un métacaractère littéral comme . ou *, échappez-le avec une barre oblique inverse : \. correspond à un vrai point.

Séquences spéciales

Les séquences spéciales sont des classes de caractères abrégées qui apparaissent fréquemment dans les motifs réels.

SéquenceCorrespond à
\dN'importe quel chiffre — équivalent à [0-9]
\DN'importe quel caractère non-chiffre
\wCaractère de mot : lettres, chiffres, underscore
\WCaractère non-mot
\sEspace blanc : espace, tabulation, saut de ligne
\SCaractère non-espace
\bLimite de mot (largeur nulle)
\BNon-limite de mot
import re

print(re.findall(r'\d+', 'I have 3 cats and 12 dogs'))
# ['3', '12']

print(re.findall(r'\w+', 'hello_world 123'))
# ['hello_world', '123']

print(re.findall(r'\bPython\b', 'Python Pythonista Python3'))
# ['Python']  — word boundary prevents partial matches

\b est particulièrement utile : il correspond à la position entre un caractère de mot et un caractère non-mot, donc \bPython\b correspond au mot autonome « Python » mais pas à « Pythonista » ou « Python3 ».

Quantificateurs

Les quantificateurs contrôlent le nombre de fois que l'élément précédent doit correspondre.

import re

print(re.findall(r'a*', 'baaa'))   # ['', 'aaa', '']
print(re.findall(r'a+', 'baaa'))   # ['aaa']
print(re.findall(r'a?', 'baaa'))   # ['', 'a', 'a', 'a', '']
print(re.findall(r'a{3}', 'baaa')) # ['aaa']

Correspondance gourmande vs paresseuse

Par défaut, les quantificateurs sont gourmands — ils correspondent à autant de texte que possible. Ajoutez ? après le quantificateur pour le rendre paresseux (correspondance minimale possible).

import re

html = '<b>bold</b> and <i>italic</i>'

print(re.findall(r'<.*>', html))
# ['<b>bold</b> and <i>italic</i>']  — greedy: matches from first < to last >

print(re.findall(r'<.*?>', html))
# ['<b>', '</b>', '<i>', '</i>']  — lazy: matches each individual tag

Les quantificateurs paresseux sont essentiels pour analyser du texte structuré comme HTML ou des fragments JSON.

Classes de caractères

Une classe de caractères [...] correspond à n'importe quel caractère de l'ensemble listé. Utilisez - pour les plages et ^ au début pour nier la classe.

import re

print(re.findall(r'[aeiou]', 'hello world'))
# ['e', 'o', 'o']

print(re.findall(r'[0-9]', 'a1b2c3'))
# ['1', '2', '3']

print(re.findall(r'[^aeiou\s]+', 'hello world'))
# ['h', 'll', 'w', 'rld']  — consonants only (not vowels, not spaces)

Plages prédéfinies courantes : [a-z] lettres minuscules, [A-Z] majuscules, [0-9] chiffres, [a-zA-Z0-9] alphanumériques.

Ancres

Les ancres ne consomment pas de caractères — elles affirment une position dans la string.

import re

print(re.findall(r'^Python', 'Python is great'))
# ['Python']  — matches only if 'Python' is at the start

print(re.findall(r'great$', 'Python is great'))
# ['great']  — matches only if 'great' is at the end

print(re.findall(r'^Python', 'Learn Python'))
# []  — 'Python' is not at the start of this string

Consultez le drapeau re.MULTILINE plus loin dans ce chapitre pour appliquer ^ et $ par ligne plutôt que par string.

Alternation

Le pipe | fonctionne comme un OU logique entre deux expressions.

import re

print(re.findall(r'cat|dog', 'I have a cat and a dog'))
# ['cat', 'dog']

print(re.findall(r'colou?r|colour', 'color and colour'))
# ['color', 'colour']

Groupes capturants

Les parenthèses () créent un groupe capturant. Les groupes vous permettent d'extraire des sous-parties d'une correspondance. re.search() renvoie un objet de correspondance ; appelez .group(n) ou .groups() dessus.

import re

match = re.search(r'(\d{4})-(\d{2})-(\d{2})', '2023-10-05')
if match:
    print(match.group(0))   # '2023-10-05'  — entire match
    print(match.group(1))   # '2023'
    print(match.groups())   # ('2023', '10', '05')

Groupes nommés

Nommez un groupe avec (?P<name>...) pour y accéder par son nom plutôt que par sa position. Cela rend les motifs beaucoup plus faciles à maintenir.

import re

match = re.search(
    r'(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})',
    '2023-10-05'
)
if match:
    print(match.group('year'))   # '2023'
    print(match.groupdict())     # {'year': '2023', 'month': '10', 'day': '05'}

Groupes non-capturants

Utilisez (?:...) lorsque vous avez besoin de grouper sans capturer la valeur.

import re

print(re.findall(r'(?:Mr|Mrs|Ms)\.? \w+', 'Mr. Smith and Mrs. Jones'))
# ['Mr. Smith', 'Mrs. Jones']

Lookahead et Lookbehind

Le lookahead ((?=...)) et le lookbehind ((?<=...)) vérifient qu'un élément suit ou précède la correspondance, sans l'inclure dans le résultat. Ils sont de largeur nulle : ils ne consomment aucun caractère.

import re

# Positive lookahead — find numbers followed by 'dollars'
print(re.findall(r'\d+(?= dollars)', '100 dollars and 200 euros'))
# ['100']

# Negative lookahead — find numbers NOT followed by 'dollars'
print(re.findall(r'\b\d+\b(?! dollars)', '100 dollars and 200 euros'))
# ['200']

# Positive lookbehind — extract domain from email addresses
emails = 'Contact [email protected] or [email protected]'
print(re.findall(r'(?<=@)\w+\.\w+', emails))
# ['example.com', 'test.org']

Les motifs de lookbehind doivent avoir une largeur fixe en Python — vous ne pouvez pas utiliser * ou + à l'intérieur.

Le module re : fonctions principales

re.search() — Trouver la première correspondance

Renvoie un objet de correspondance pour le premier emplacement où le motif correspond, ou None s'il n'y a pas de correspondance.

import re

text = 'apple banana apple'
match = re.search(r'banana', text)
if match:
    print(match.group())   # 'banana'
    print(match.span())    # (6, 12)

re.match() — Correspondance au début uniquement

Comme re.search(), mais le motif doit correspondre au début de la string.

import re

print(bool(re.match(r'\d+', 'abc123')))   # False — no digit at start
print(bool(re.search(r'\d+', 'abc123')))  # True  — digit found anywhere

Utilisez re.search() lorsque vous voulez trouver un motif n'importe où ; utilisez re.match() lorsque le motif doit apparaître au début.

re.fullmatch() — Correspondance sur toute la string

Le motif doit correspondre à la totalité de la string du début à la fin.

import re

print(bool(re.fullmatch(r'\d{5}', '12345')))   # True  — exactly 5 digits
print(bool(re.fullmatch(r'\d{5}', '123456')))  # False — too long
print(bool(re.fullmatch(r'\d{5}', '1234X')))   # False — non-digit present

re.fullmatch() est idéal pour la validation des saisies (codes postaux, numéros de téléphone, etc.).

re.findall() — Toutes les correspondances non-chevauchantes

Renvoie une liste de toutes les correspondances. Si le motif contient des groupes, renvoie une liste de tuples.

import re

print(re.findall(r'\d+', 'abc 123 def 456'))
# ['123', '456']

# With a group — returns list of group values
print(re.findall(r'(\w+)@(\w+\.\w+)', '[email protected] [email protected]'))
# [('alice', 'example.com'), ('bob', 'test.org')]

re.finditer() — Itérateur d'objets de correspondance

Comme re.findall(), mais produit des objets de correspondance un à la fois. Utile pour les grands textes ou lorsque vous avez besoin des informations de position.

import re

for m in re.finditer(r'\d+', 'abc 123 def 456'):
    print(m.group(), m.start(), m.end())
# 123 4 7
# 456 12 15

re.sub() — Remplacer les correspondances

Remplace chaque occurrence du motif par une string de remplacement ou la valeur de retour d'une fonction.

import re

text = 'apple banana apple'
print(re.sub(r'apple', 'orange', text))
# 'orange banana orange'

# Limit replacements
print(re.sub(r'apple', 'orange', text, count=1))
# 'orange banana apple'

# Backreferences in replacement — reformat a date
print(re.sub(r'(\d{4})-(\d{2})-(\d{2})', r'\3/\2/\1', '2023-10-05'))
# '05/10/2023'

re.split() — Diviser par un motif

Divise la string à chaque occurrence du motif.

import re

print(re.split(r',\s*', 'apple, banana, cherry, date'))
# ['apple', 'banana', 'cherry', 'date']

# Limit the number of splits
print(re.split(r',\s*', 'apple, banana, cherry, date', maxsplit=2))
# ['apple', 'banana', 'cherry, date']

Compiler des motifs avec re.compile()

Lorsque vous utilisez le même motif plusieurs fois, compilez-le une fois avec re.compile() pour améliorer les performances. L'objet motif résultant dispose de toutes les mêmes méthodes (findall, search, sub, etc.).

import re

# Compile once
digit_pattern = re.compile(r'\d+')

# Reuse many times
print(digit_pattern.findall('abc 123 def 456'))   # ['123', '456']
print(digit_pattern.sub('NUM', 'abc 123 def 456')) # 'abc NUM def NUM'
print(digit_pattern.search('xyz 99'))              # <re.Match object ...>

La compilation est particulièrement utile à l'intérieur de boucles ou de fonctions appelées fréquemment.

Drapeaux (Flags)

Les drapeaux modifient le comportement de la correspondance. Passez-les comme dernier argument à n'importe quelle fonction re, ou incluez-les lors de l'appel à re.compile(). Plusieurs drapeaux peuvent être combinés avec |.

DrapeauForme abrégéeEffet
re.IGNORECASEre.ICorrespondance insensible à la casse
re.MULTILINEre.M^ et $ correspondent au début/fin de chaque ligne
re.DOTALLre.S. correspond aussi aux sauts de ligne
re.VERBOSEre.XAutoriser les espaces et commentaires dans le motif
import re

# IGNORECASE
print(re.findall(r'hello', 'Hello HELLO hello', re.IGNORECASE))
# ['Hello', 'HELLO', 'hello']

# MULTILINE — ^ matches the start of each line
text = 'first line\nsecond line\nthird line'
print(re.findall(r'^\w+', text, re.MULTILINE))
# ['first', 'second', 'third']

# DOTALL — . matches newline characters
print(re.findall(r'<.*?>', '<div>\n<p>text</p>\n</div>', re.DOTALL))
# ['<div>', '<p>', '</p>', '</div>']

# VERBOSE — write readable patterns with comments
date_pattern = re.compile(r'''
    (?P<year>\d{4})   # four-digit year
    -
    (?P<month>\d{2})  # two-digit month
    -
    (?P<day>\d{2})    # two-digit day
''', re.VERBOSE)
print(date_pattern.search('2023-10-05').groupdict())
# {'year': '2023', 'month': '10', 'day': '05'}

Échapper les saisies utilisateur avec re.escape()

Si vous construisez un motif à partir d'un texte fourni par l'utilisateur, échappez-le toujours en premier pour éviter une interprétation involontaire des métacaractères.

import re

user_input = 'hello.world'
# Without escaping, '.' matches any character
# With escaping, '\.' matches a literal dot
safe_pattern = re.escape(user_input)
print(safe_pattern)                                    # 'hello\\.world'
print(bool(re.search(safe_pattern, 'say hello.world')))  # True
print(bool(re.search(safe_pattern, 'say helloXworld')))  # False

Exemples pratiques

Valider une adresse e-mail

import re

def is_valid_email(email):
    pattern = r'^[\w.+-]+@[\w-]+\.[a-zA-Z]{2,}$'
    return bool(re.fullmatch(pattern, email))

print(is_valid_email('[email protected]'))   # True
print(is_valid_email('bad-email@'))         # False

Extraire toutes les URL d'un texte

import re

text = 'Visit https://www.example.com or http://test.org for details.'
urls = re.findall(r'https?://[\w./-]+', text)
print(urls)
# ['https://www.example.com', 'http://test.org']

Supprimer les espaces superflus

import re

messy = '  hello    world   Python  '
clean = re.sub(r'\s+', ' ', messy).strip()
print(clean)  # 'hello world Python'

Analyser une ligne de journal

import re

log = '2023-10-05 14:32:11 ERROR Failed to connect to database'
pattern = re.compile(
    r'(?P<date>\d{4}-\d{2}-\d{2}) '
    r'(?P<time>\d{2}:\d{2}:\d{2}) '
    r'(?P<level>\w+) '
    r'(?P<message>.+)'
)
m = pattern.match(log)
if m:
    print(m.group('level'))    # 'ERROR'
    print(m.group('message'))  # 'Failed to connect to database'

Pièges courants

re.match() vs re.search()re.match() vérifie uniquement le début de la string. Les nouveaux utilisateurs s'attendent souvent à ce qu'il recherche n'importe où et sont confus lorsqu'il renvoie None.

Oublier les chaînes brutes'\d' dans une string Python normale est simplement 'd' avec un échappement non reconnu (ou un SyntaxWarning en Python 3.12+). Écrivez toujours r'\d'.

Les correspondances gourmandes qui capturent trop — Si un motif .* capture plus que prévu, passez à .*? (paresseux).

Caractères spéciaux dans les strings de remplacement — Dans re.sub(), les séquences avec barre oblique inverse comme \1 dans le remplacement font référence aux groupes capturés. Pour inclure une barre oblique inverse littérale dans le remplacement, écrivez \\.

re.findall() avec des groupes — Lorsque votre motif contient des groupes, re.findall() renvoie les groupes, pas la correspondance complète. Utilisez un groupe non-capturant (?:...) si vous voulez la correspondance complète.

Référence rapide

TâcheFonction
Trouver la première correspondancere.search(pattern, text)
Trouver toutes les correspondancesre.findall(pattern, text)
Itérer les correspondancesre.finditer(pattern, text)
Correspondance au débutre.match(pattern, text)
Correspondance sur toute la stringre.fullmatch(pattern, text)
Remplacerre.sub(pattern, repl, text)
Diviserre.split(pattern, text)
Compiler pour réutilisationre.compile(pattern)
Échapper les saisies utilisateurre.escape(text)

Chapitres associés

  • Python Strings — méthodes de string qui complètent les regex pour des tâches textuelles plus simples.
  • Modify Strings — méthodes intégrées comme replace() et split() qui évitent les regex lorsque les motifs sont fixes.
  • Python File Handling — lecture de fichiers ligne par ligne pour appliquer les regex à grande échelle.
  • Python Try/Except — gestion des erreurs qui surviennent lorsque les motifs regex sont compilés à partir de saisies utilisateur.
  • Python Functions — encapsuler la logique regex dans des fonctions réutilisables.

Pratique

Pratique
What does the 're' module in Python provide?
What does the 're' module in Python provide?
Was this page helpful?