Maîtrise des expressions régulières en Python avec le module re

Métacaractères de base

Le module re implémente un moteur d’expressions régulières. Voici les symboles les plus courants :

Symbole Signification
. Tout caractère sauf le saut de ligne (par défaut)
\d Un chiffre, équivalent à [0-9]
\D Tout caractère non numérique
\w Un caractère de mot (lettre, chiffre ou souligné)
\W Tout caractère n’étant pas un caractère de mot
\s Un espace blanc (espace, tabulation, saut de ligne…)
\S Tout caractère n’étant pas un espace blanc
\b Une limite de mot
\B Une position qui n’est pas une limite de mot
[a-z] Une lettre minuscule
[^a-z] Un caractère qui n’est pas une lettre minuscule

Pour utiliser un métacaractère en tant que caractère littéral, il faut l’échapper avec un antislash. L’antislash lui-même s’écrit \\.

Quantificateurs

Quantificateur Signification Exemple
* Zéro occurrence ou plus a\w* : un « a » suivi de zero ou plusieurs caractères de mot
+ Une occurrence ou plus a\w+ : au moins un caractère de mot après le « a »
? Zéro ou une occurrence colou?r : « color » ou « colour »
{n} Exactement n occurrences \d{3} : exactement trois chiffres
{n,} Au moins n occurrences \w{2,} : au moins deux caractères de mot
{n,m} Entre n et m occurrences \w{1,10} : de 1 à 10 caractères de mot

Par défaut, les quantificateurs sont gourmands : ils consomment le plus de caractères possible. Pour obtenir un comportement non gourmand, on ajoute un ? après le quantificateur : *?, +?, ??, {n,m}?.

Alternance, regroupements et assertions

  • (expression) : capture un groupe et lui attribue un numéro.
  • (?:expression) : regroupe sans capturer.
  • (?P<nom>expression) : capture un groupe nommé accessible via son nom.
  • (?=...) : assertion de prévision positive (ce qui suit doit correspondre, sans être consommé).
  • (?!...) : assertion de prévision négative (ce qui suit ne doit pas correspondre).
  • (<=...) : assertion de rétrospection positive.
  • (? <! ...) : assertion de rétrospection négative.

Les assertions ne capturent pas de texte et ne créent pas de groupe.

Drapeaux du module re

Drapeau Effet
re.I ou re.IGNORECASE Ignorer la casse
re.S ou re.DOTALL Le point . correspond aussi au saut de ligne
re.M ou re.MULTILINE ^ et $ correspondent au début et à la fin de chaque ligne
re.X ou re.VERBOSE Permet d’écrire le motif sur plusieurs lignes avec des commentaires

On combine les drapeaux avec l’opérateur OU bit à bit : re.I | re.S.

Compilation d’un motif

La fonction re.compile transforme une chaîne de caractères en objet motif réutilisable, ce qui améliore les performances lors de recherches multiples.

import re

motif = re.compile(r'\d{2,4}', re.ASCII)
print(motif, type(motif))
# <re.Match object; ...>

Recherche de correspondances

Différentes fonctions permettent de rechercher un motif dans une chaîne :

  • re.match(motif, texte) : teste une corresponadnce uniquement au début de la chaîne.
  • re.search(motif, texte) : parcourt la chaîne et retourne la première correspondance trouvée.
  • re.fullmatch(motif, texte) : exige que le motif corresponde à l’ensemble de la chaîne.
import re

phrase = "Château 123, appartement 4B"
mot_nombre = re.compile(r'\d+')

debut = mot_nombre.match(phrase)
premier = mot_nombre.search(phrase)
entier = re.fullmatch(r'[A-Za-z0-9\s,]+', phrase)

print(debut.group() if debut else None)  # None
print(premier.group())                    # 123
print(entier is not None)                 # True

Recherche de toutes les occurrences

re.findall retourne une liste des correspondances, tandis que re.finditer retourne un itérateur d’objets Match.

import re

texte = "Prix : 12€, 45€ et 8€"
motif_prix = re.compile(r'\d+')

liste = motif_prix.findall(texte)
iterateur = motif_prix.finditer(texte)

print(liste)  # ['12', '45', '8']
for occurrence in iterateur:
    print(occurrence.group(), occurrence.span())

Substitution et découpage

re.sub remplace les correspondances par une chaîne ou une fonction. re.subn retourne en plus le nombre de remplacements effectués. re.split découpe la chaîne selon un motif.

import re

adresse = "route.des.champs@exemple.fr"
motif_point = re.compile(r'\.')
parties = motif_point.split(adresse)
print(parties)
# ['route', 'des', 'champs@exemple', 'fr']

masque = re.sub(r'[^@]+', '***', adresse, count=1)
print(masque)  # ***@exemple.fr

resultat, nb = re.subn(r'\d+', 'N', 'Année 2024, version 2')
print(resultat, nb)  # Année N, version N 2

Groupes et extraction

Les parenthèses capturent des sous-parties du motif. On accède au groupe complet avec group(0) ou group(), aux groupes numérotés avec group(n), à l’ensemble des groupes avec groups(), et aux groupes nommés avec groupdict().

import re

ligne = "Fichier: rapport_2024.pdf, taille: 2048 Ko"
motif_fichier = re.compile(r'Fichier:\s+((.+?)_(\d{4})\.(\w+)).+?(\d+)\s+Ko', re.I)

m = motif_fichier.search(ligne)
if m:
    print(m.group(0))     # correspondance complète
    print(m.group(1))     # nom du fichier complet
    print(m.group(2))     # base du nom
    print(m.group(3))     # année
    print(m.group(4))     # extension
    print(m.group(5))     # taille
    print(m.groups())

Les groupes nommés utilisent la syntaxe (?P<nom>...) et facilitent la lisibilité du code.

Étiquettes: Python re Expressions Régulières regex matching textuel

Publié le 4 juillet à 17h00