Contactez-nous

Syntaxe des expressions régulières (caractères spéciaux, quantificateurs...)

Maîtrisez la syntaxe des expressions régulières en Python. Découvrez la signification des caractères spéciaux (. * + ? [] ^ $ \ | ()), des quantificateurs ({}, *, +, ?), des classes de caractères, et des séquences spéciales.

Caractères littéraux et caractères spéciaux (métacaractères)

Dans une expression régulière, la plupart des caractères se représentent eux-mêmes. Par exemple, le motif `abc` correspond simplement à la chaîne "abc".

Cependant, certains caractères ont une signification spéciale. Ce sont les *caractères spéciaux* (ou *métacaractères*) : `.^$*+?{}[]\|()`. Pour utiliser ces caractères littéralement, vous devez les *échapper* en les précédant d'un antislash (`\`).

Exemple :

import re

# Pour rechercher le caractère '.' (point), il faut l'échapper :
texte = "Un point, c'est tout."
motif = "\."
resultat = re.search(motif, texte)  # Trouve le point

# Sans l'échappement, '.' correspondrait à n'importe quel caractère :
motif = "." # Correspond à 'U', 'n', ' ', 'p', ...

# Pour rechercher une accolade ouvrante : \{
# Pour rechercher un antislash : \\

Classes de caractères : [] et [^]

Les crochets `[]` permettent de définir une *classe de caractères*, c'est-à-dire un ensemble de caractères possibles.

  • `[abc]` : Correspond à `a`, `b`, ou `c`.
  • `[a-z]` : Correspond à n'importe quelle lettre minuscule (de `a` à `z`).
  • `[A-Z]` : Correspond à n'importe quelle lettre majuscule.
  • `[0-9]` : Correspond à n'importe quel chiffre.
  • `[a-zA-Z0-9]` : Correspond à n'importe quelle lettre (minuscule ou majuscule) ou chiffre.

A l'intérieur de crochets, la plupart des caractères spéciaux perdent leur signification spéciale et sont interprétés littéralement (sauf `^`, `-`, `]` et `\`).

Le `^` (circonflexe), placé *immédiatement après le crochet ouvrant*, a une signification spéciale : il *inverse* la classe de caractères.

  • `[^abc]` : Correspond à n'importe quel caractère *sauf* `a`, `b`, ou `c`.
  • `[^0-9]` : Correspond à n'importe quel caractère qui n'est *pas* un chiffre.

Exemples :

import re

# Trouver une voyelle
texte = "Bonjour"
motif = "[aeiouyAEIOUY]"
resultat = re.search(motif, texte)
print(resultat.group(0))  # Affiche 'o'

# Trouver un caractère non alphanumérique
texte = "Hello_World!123"
motif = "[^a-zA-Z0-9_]"
resultat = re.search(motif, texte)  # Trouve '!'
print(resultat.group(0))

Quantificateurs : *, +, ?, {}

Les *quantificateurs* permettent de spécifier le nombre de répétitions d'un caractère, d'un groupe, ou d'une classe de caractères.

  • `*` (astérisque) : Zéro, une ou plusieurs répétitions de l'élément précédent.
  • `+` (plus) : Une ou plusieurs répétitions de l'élément précédent.
  • `?` (point d'interrogation) : Zéro ou une répétition de l'élément précédent.
  • `{n}` : Exactement `n` répétitions de l'élément précédent.
  • `{n,}` : Au moins `n` répétitions de l'élément précédent.
  • `{n,m}` : Entre `n` et `m` répétitions (inclus) de l'élément précédent.

Exemples :

import re

# "ab*" : 'a' suivi de zéro, une ou plusieurs occurrences de 'b'
print(re.search(r"ab*", "a"))     # Trouve 'a'
print(re.search(r"ab*", "ab"))    # Trouve 'ab'
print(re.search(r"ab*", "abbb"))  # Trouve 'abbb'

# "ab+" : 'a' suivi d'au moins une occurrence de 'b'
print(re.search(r"ab+", "a"))     # None
print(re.search(r"ab+", "ab"))    # Trouve 'ab'

# "ab?" : 'a' suivi de zéro ou une occurrence de 'b'
print(re.search(r"ab?", "a"))     # Trouve 'a'
print(re.search(r"ab?", "ab"))    # Trouve 'ab'
print(re.search(r"ab?", "abbb"))  # Trouve 'ab' (le premier)

# "a{3}" : exactement 3 'a'
print(re.search(r"a{3}", "aa"))   # None
print(re.search(r"a{3}", "aaa"))  # Trouve 'aaa'

# "a{2,}" : au moins 2 'a'
print(re.search(r"a{2,}", "a"))     # None
print(re.search(r"a{2,}", "aa"))    # Trouve 'aa'
print(re.search(r"a{2,}", "aaaaa")) # Trouve 'aaaaa'

# "a{2,4}" : entre 2 et 4 'a'
print(re.search(r"a{2,4}", "a"))     # None
print(re.search(r"a{2,4}", "aa"))    # Trouve 'aa'
print(re.search(r"a{2,4}", "aaaa"))  # Trouve 'aaaa'
print(re.search(r"a{2,4}", "aaaaa")) # Trouve 'aaaa' (les 4 premiers)

Par défaut, les quantificateurs sont "gourmands" (greedy), c'est-à-dire qu'ils essaient de correspondre à la plus grande séquence possible. Vous pouvez les rendre "non gourmands" (lazy) en ajoutant un `?` après le quantificateur (par exemple, `*?`, `+?`, `??`, `{n,}?`).

Le point (.) : n'importe quel caractère (sauf saut de ligne)

Le point `.` (dans le mode par défaut) correspond à *n'importe quel caractère*, sauf un saut de ligne (`\n`).

Exemple :

import re

# ".+" : un ou plusieurs caractères quelconques
print(re.search(r".+", "Bonjour le monde"))  # Trouve toute la chaîne

# "a.c" : 'a', suivi d'un caractère quelconque, suivi de 'c'
print(re.search(r"a.c", "abc"))  # Trouve 'abc'
print(re.search(r"a.c", "a1c"))  # Trouve 'a1c'
print(re.search(r"a.c", "ac"))   # None

Si vous voulez que le point corresponde *aussi* aux sauts de ligne, vous pouvez utiliser le flag `re.DOTALL` (voir la section sur les fonctions du module `re`).

Ancres : ^ et $ (début et fin de chaîne)

  • `^` (circonflexe) : Correspond au *début* de la chaîne (ou au début de chaque ligne, en mode multiligne).
  • `$` (dollar) : Correspond à la *fin* de la chaîne (ou à la fin de chaque ligne, en mode multiligne).

Exemples :

import re

# "^Bonjour" : la chaîne doit commencer par "Bonjour"
print(re.search(r"^Bonjour", "Bonjour le monde"))  # Trouve
print(re.search(r"^Bonjour", "Le monde Bonjour"))  # None

# "monde$" : la chaîne doit se terminer par "monde"
print(re.search(r"monde$", "Bonjour le monde"))  # Trouve
print(re.search(r"monde$", "Le monde Bonjour"))  # None

Alternation : | (OU logique)

La barre verticale `|` permet de spécifier une alternative (un choix entre plusieurs motifs).

Exemple :

import re

# "chat|chien" : correspond à "chat" ou "chien"
print(re.search(r"chat|chien", "J'ai un chat."))  # Trouve 'chat'
print(re.search(r"chat|chien", "J'ai un chien."))  # Trouve 'chien'
print(re.search(r"chat|chien", "J'ai un oiseau.")) # None

Groupes : ()

Les parenthèses `()` permettent de grouper des parties d'une expression régulière.

Les groupes ont plusieurs utilités :

  • Appliquer un quantificateur à un groupe : Par exemple, `(ab)+` correspond à une ou plusieurs répétitions de la séquence "ab".
  • Définir des alternatives à l'intérieur d'un groupe : Par exemple, `(a|b)c` correspond à "ac" ou "bc".
  • Capturer des groupes : Par défaut, les groupes sont *capturants*, ce qui signifie que la partie de la chaîne qui correspond au groupe est mémorisée et peut être récupérée ultérieurement (voir la section sur les fonctions du module `re`).
  • Faire référence à un groupe capturé plus tôt dans l'expression régulière (backreferences, voir plus loin).

Exemple :

import re

# "(ab)+" : une ou plusieurs répétitions de "ab"
print(re.search(r"(ab)+", "ab"))        # Trouve 'ab'
print(re.search(r"(ab)+", "ababab"))  # Trouve 'ababab'
print(re.search(r"(ab)+", "ac"))        # None

# "(a|b)c" : 'a' ou 'b', suivi de 'c'
print(re.search(r"(a|b)c", "ac"))  # Trouve 'ac'
print(re.search(r"(a|b)c", "bc"))  # Trouve 'bc'
print(re.search(r"(a|b)c", "dc"))  # None

Séquences spéciales : \d, \w, \s, etc.

Python définit plusieurs *séquences spéciales* qui représentent des ensembles de caractères courants. Ces séquences spéciales commencent par un antislash `\` suivi d'une lettre.

Voici quelques séquences spéciales courantes :

  • `\d` : Correspond à n'importe quel chiffre (équivalent à `[0-9]`).
  • `\D` : Correspond à n'importe quel caractère qui n'est *pas* un chiffre (équivalent à `[^0-9]`).
  • `\w` : Correspond à n'importe quel caractère alphanumérique (lettres, chiffres, et le trait de soulignement `_`) (équivalent à `[a-zA-Z0-9_]` pour les chaînes ASCII). Dans les chaînes Unicode, correspond aussi aux caractères considérés comme des lettres ou des chiffres dans d'autres alphabets.
  • `\W` : Correspond à n'importe quel caractère qui n'est *pas* alphanumérique.
  • `\s` : Correspond à n'importe quel caractère "blanc" (espace, tabulation, saut de ligne, etc.).
  • `\S` : Correspond à n'importe quel caractère qui n'est *pas* un caractère "blanc".
  • `\b` : Correspond à une limite de mot (word boundary), c'est à dire entre un caractère `\w` et un caractère `\W`, ou entre un caractère `\w` et le début/fin de la chaîne.
  • `\B` : Correspond à une position qui n'est *pas* une limite de mot.

Exemples :

import re

# "\d+" : un ou plusieurs chiffres
print(re.search(r"\d+", "Il y a 123 pommes."))  # Trouve '123'

# "\w+" : un ou plusieurs caractères alphanumériques (un "mot")
print(re.search(r"\w+", "Bonjour le_monde!"))  # Trouve 'Bonjour'

# "\s+" : un ou plusieurs espaces
print(re.search(r"\s+", "Bonjour   le monde"))  # Trouve '   ' (les trois espaces)

Ces séquences spéciales peuvent être utilisées à l'intérieur ou à l'extérieur des classes de caractères (`[]`).

Echappement : \

L'antislash `\` a une double fonction dans les expressions régulières :

  • Il permet d'échapper les caractères spéciaux pour qu'ils soient interprétés littéralement (par exemple, `\.` pour rechercher un point, `\*` pour rechercher une astérisque, `\(` pour une parenthèse ouvrante, etc.).
  • Il introduit les séquences spéciales (comme `\d`, `\w`, `\s`, etc.).

Si vous voulez rechercher un antislash littéral, vous devez l'échapper lui-même : `\\`.

Exemple :

import re

# Rechercher une chaîne contenant un point (échappé)
print(re.search(r"\.", "abc.def"))  # Trouve '.'

# Rechercher une chaîne contenant un antislash (échappé)
print(re.search(r"\\", "a\\b"))    # Trouve '\\'

Pour éviter d'avoir à échapper les antislashs eux-mêmes, vous pouvez utiliser des *chaînes brutes* (raw strings) pour définir vos expressions régulières. Une chaîne brute est préfixée par un `r` (ou `R`) avant le guillemet ouvrant. Dans une chaîne brute, les antislashs sont interprétés littéralement.

Exemple (avec une chaîne brute) :

import re

# Rechercher une chaîne contenant un antislash (avec une chaîne brute)
print(re.search(r"\", "a\b"))    # Trouve '\\'

Il est *fortement recommandé* d'utiliser des chaînes brutes pour définir vos expressions régulières en Python, pour éviter les confusions et les erreurs liées à l'échappement des antislashs.

Quantificateurs non gourmands (lazy)

Par défaut, les quantificateurs (`*`, `+`, `?`, `{}`) sont "gourmands" (greedy). Cela signifie qu'ils essaient de correspondre à la plus *longue* chaîne possible.

Vous pouvez rendre un quantificateur "non gourmand" (lazy, ou minimal) en ajoutant un `?` après le quantificateur.

Un quantificateur non gourmand essaie de correspondre à la plus *courte* chaîne possible.

Exemple :

import re

texte = "texte 1 et texte 2"

# Gourmand (greedy) : correspond au plus long possible
motif_gourmand = r"<.+>"
print(re.search(motif_gourmand, texte).group(0)) # texte 1 et texte 2

# Non gourmand (lazy) : correspond au plus court possible
motif_non_gourmand = r"<.+?>"
print(re.search(motif_non_gourmand, texte).group(0))  # 

Dans cet exemple, le motif gourmand `<.+>` correspond à toute la chaîne entre la *première* balise ouvrante `<` et la *dernière* balise fermante `>`. Le motif non gourmand `<.+?>` correspond à la plus courte chaîne possible entre `<` et `>`, c'est-à-dire la première balise ouvrante ``.

Les quantificateurs non gourmands sont : `*?`, `+?`, `??`, `{n,}?`.