Expressions Régulières
Une expression régulière (raccourcie en regex [...]) est une séquence de caractères qui spécifie un modèle de recherche dans un texte. [...] utilisée par les algorithmes de recherche de chaînes pour les opérations de "trouver" ou de "trouver et remplacer" sur des chaînes, ou pour la validation des entrées.
- Importez le module regex avec
import re. - Créez un objet Regex avec la fonction
re.compile(). (N’oubliez pas d’utiliser une chaîne brute.) - Passez la chaîne que vous souhaitez rechercher à la méthode
search()de l’objet Regex. Cela renvoie un objetMatch. - Appelez la méthode
group()de l’objet Match pour renvoyer une chaîne du texte réellement correspondant.
Toutes les fonctions regex en Python se trouvent dans le module re :
# Importez le module re pour les opérations d'expression régulière
import re
Symboles Regex
| Symbole | Correspond à |
|---|---|
? | zéro ou une fois du groupe précédent. |
* | zéro ou plusieurs fois du groupe précédent. |
+ | une ou plusieurs fois du groupe précédent. |
{n} | exactement n fois du groupe précédent. |
{n,} | n fois ou plus du groupe précédent. |
{,m} | 0 à m fois du groupe précédent. |
{n,m} | au moins n et au plus m fois du p précédent. |
{n,m}? ou *? ou +? | effectue une correspondance non gourmande du p précédent. |
^spam | signifie que la chaîne doit commencer par spam. |
spam$ | signifie que la chaîne doit se terminer par spam. |
. | tout caractère, sauf les caractères de nouvelle ligne. |
\d, \w, et \s | un chiffre, un mot, ou un caractère d’espace, respectivement. |
\D, \W, et \S | tout sauf un chiffre, un mot, ou un espace, respectivement. |
[abc] | tout caractère entre les crochets (comme a, b, ). |
[^abc] | tout caractère qui n’est pas entre les crochets. |
Objets regex correspondants
# re.compile(): créer un objet de motif regex (utiliser une chaîne brute r'' pour éviter l'échappement)
phone_num_regex = re.compile(r'\d\d\d-\d\d\d-\d\d\d\d') # Motif : 3 chiffres-3 chiffres-4 chiffres
mo = phone_num_regex.search('My number is 415-555-4242.') # Rechercher le motif
print(f'Phone number found: {mo.group()}') # group() renvoie le texte correspondant
Phone number found: 415-555-4242
Groupement avec parenthèses
# Les parenthèses créent des groupes : group(1) renvoie le premier groupe, group(2) renvoie le deuxième
phone_num_regex = re.compile(r'(\d\d\d)-(\d\d\d-\d\d\d\d)') # Deux groupes entre parenthèses
mo = phone_num_regex.search('My number is 415-555-4242.')
mo.group(1) # Renvoie le premier groupe : '415'
'415'
mo.group(2)
'555-4242'
mo.group(0)
'415-555-4242'
mo.group()
'415-555-4242'
Connectez-vous pour répondre à ce quiz et suivre votre progression d'apprentissage
group() lorsqu'il est appelé sur un objet match ?Pour récupérer tous les groupes en une seule fois, utilisez la méthode groups() :
# groups(): renvoie un tuple de tous les groupes
mo.groups() # Renvoie ('415', '555-4242')
('415', '555-4242')
area_code, main_number = mo.groups()
print(area_code)
415
print(main_number)
555-4242
Groupement multiple avec Pipe
Vous pouvez utiliser le caractère | partout où vous souhaitez faire correspondre une de plusieurs expressions.
hero_regex = re.compile (r'Batman|Tina Fey')
mo1 = hero_regex.search('Batman and Tina Fey.')
mo1.group()
'Batman'
mo2 = hero_regex.search('Tina Fey and Batman.')
mo2.group()
'Tina Fey'
Vous pouvez également utiliser le pipe pour faire correspondre un de plusieurs motifs dans le cadre de votre regex :
bat_regex = re.compile(r'Bat(man|mobile|copter|bat)')
mo = bat_regex.search('Batmobile lost a wheel')
mo.group()
'Batmobile'
mo.group(1)
'mobile'
Correspondance optionnelle avec le point d’interrogation
Le caractère ? signale le groupe qui le précède comme étant une partie optionnelle du motif.
bat_regex = re.compile(r'Bat(wo)?man')
mo1 = bat_regex.search('The Adventures of Batman')
mo1.group()
'Batman'
mo2 = bat_regex.search('The Adventures of Batwoman')
mo2.group()
'Batwoman'
Correspondance zéro ou plusieurs fois avec l’étoile
Le * (étoile ou astérisque) signifie “faire correspondre zéro ou plusieurs fois”. Le groupe précédant l’étoile peut apparaître n’importe quel nombre de fois dans le texte.
bat_regex = re.compile(r'Bat(wo)*man')
mo1 = bat_regex.search('The Adventures of Batman')
mo1.group()
'Batman'
mo2 = bat_regex.search('The Adventures of Batwoman')
mo2.group()
'Batwoman'
mo3 = bat_regex.search('The Adventures of Batwowowowoman')
mo3.group()
'Batwowowowoman'
Correspondance une ou plusieurs fois avec le Plus
Le + (ou plus) signifie faire correspondre une ou plusieurs fois. Le groupe précédant un plus doit apparaître au moins une fois :
bat_regex = re.compile(r'Bat(wo)+man')
mo1 = bat_regex.search('The Adventures of Batwoman')
mo1.group()
'Batwoman'
mo2 = bat_regex.search('The Adventures of Batwowowowoman')
mo2.group()
'Batwowowowoman'
mo3 = bat_regex.search('The Adventures of Batman')
mo3 is None
True
Correspondance de répétitions spécifiques avec les accolades
Si vous avez un groupe que vous souhaitez répéter un nombre spécifique de fois, suivez le groupe dans votre regex avec un nombre entre accolades :
ha_regex = re.compile(r'(Ha){3}')
mo1 = ha_regex.search('HaHaHa')
mo1.group()
'HaHaHa'
mo2 = ha_regex.search('Ha')
mo2 is None
True
Au lieu d’un seul nombre, vous pouvez spécifier une plage avec un minimum et un maximum entre les accolades. Par exemple, la regex (Ha){3,5} correspondra à ‘HaHaHa’, ‘HaHaHaHa’ et ‘HaHaHaHaHa’.
ha_regex = re.compile(r'(Ha){2,3}')
mo1 = ha_regex.search('HaHaHaHa')
mo1.group()
'HaHaHa'
Correspondance gourmande et non gourmande
Les expressions régulières de Python sont gourmandes par défaut : dans les situations ambiguës, elles correspondent à la chaîne la plus longue possible. La version non gourmande des accolades, qui correspond à la chaîne la plus courte possible, a l’accolade fermante suivie d’un point d’interrogation.
greedy_ha_regex = re.compile(r'(Ha){3,5}')
mo1 = greedy_ha_regex.search('HaHaHaHaHa')
mo1.group()
'HaHaHaHaHa'
non_greedy_ha_regex = re.compile(r'(Ha){3,5}?')
mo2 = non_greedy_ha_regex.search('HaHaHaHaHa')
mo2.group()
'HaHaHa'
Connectez-vous pour répondre à ce quiz et suivre votre progression d'apprentissage
_ au lieu de +? après le quantificateur (ex : _?, +?, {3,5}?)La méthode findall()
La méthode findall() renverra les chaînes de chaque correspondance dans la chaîne recherchée.
phone_num_regex = re.compile(r'\d\d\d-\d\d\d-\d\d\d\d') # n'a pas de groupes
phone_num_regex.findall('Cell: 415-555-9999 Work: 212-555-0000')
['415-555-9999', '212-555-0000']
Créer vos propres classes de caractères
Vous pouvez définir votre propre classe de caractères en utilisant des crochets. Par exemple, la classe de caractères [aeiouAEIOU] correspondra à n’importe quelle voyelle, minuscule et majuscule.
vowel_regex = re.compile(r'[aeiouAEIOU]')
vowel_regex.findall('Robocop eats baby food. BABY FOOD.')
['o', 'o', 'o', 'e', 'a', 'a', 'o', 'o', 'A', 'O', 'O']
Vous pouvez également inclure des plages de lettres ou de chiffres en utilisant un trait d’union. Par exemple, la classe de caractères [a-zA-Z0-9] correspondra à toutes les lettres minuscules, majuscules et aux chiffres.
En plaçant un caractère circonflexe (^) juste après le crochet ouvrant de la classe de caractères, vous pouvez créer une classe de caractères négative qui correspondra à tous les caractères qui ne sont pas dans la classe de caractères :
consonant_regex = re.compile(r'[^aeiouAEIOU]')
consonant_regex.findall('Robocop eats baby food. BABY FOOD.')
['R', 'b', 'c', 'p', ' ', 't', 's', ' ', 'b', 'b', 'y', ' ', 'f', 'd', '.', ' ', 'B', 'B', 'Y', ' ', 'F', 'D', '.']
Les caractères Caret et Dollar sign
Vous pouvez également utiliser le symbole circonflexe
^au début d’une regex pour indiquer qu’une correspondance doit se produire au début du texte recherché.De même, vous pouvez placer un signe dollar
$à la fin de la regex pour indiquer que la chaîne doit se terminer par ce motif regex.Et vous pouvez utiliser le
^et le$ensemble pour indiquer que la chaîne entière doit correspondre à la regex.
La chaîne d’expression régulière r'^Hello' correspond aux chaînes qui commencent par ‘Hello’ :
begins_with_hello = re.compile(r'^Hello')
begins_with_hello.search('Hello world!')
<_sre.SRE_Match object; span=(0, 5), match='Hello'>
begins_with_hello.search('He said hello.') is None
True
La chaîne d’expression régulière r'\d\$' correspond aux chaînes qui se terminent par un caractère numérique de 0 à 9 :
whole_string_is_num = re.compile(r'^\d+$')
whole_string_is_num.search('1234567890')
<_sre.SRE_Match object; span=(0, 10), match='1234567890'>
whole_string_is_num.search('12345xyz67890') is None
True
whole_string_is_num.search('12 34567890') is None
True
Le caractère Joker
Le caractère . (ou point) dans une expression régulière correspondra à tout caractère sauf une nouvelle ligne :
at_regex = re.compile(r'.at')
at_regex.findall('The cat in the hat sat on the flat mat.')
['cat', 'hat', 'sat', 'lat', 'mat']
Correspondance de tout avec Dot-Star
name_regex = re.compile(r'First Name: (.*) Last Name: (.*)')
mo = name_regex.search('First Name: Al Last Name: Sweigart')
mo.group(1)
'Al'
mo.group(2)
'Sweigart'
Le .* utilise le mode gourmand : il essaiera toujours de correspondre au texte le plus long possible. Pour faire correspondre n’importe quel texte de manière non gourmande, utilisez le point, l’étoile et le point d’interrogation (.*?). Le point d’interrogation indique à Python de faire correspondre de manière non gourmande :
non_greedy_regex = re.compile(r'<.*?>')
mo = non_greedy_regex.search('<To serve man> for dinner.>')
mo.group()
'<To serve man>'
greedy_regex = re.compile(r'<.*>')
mo = greedy_regex.search('<To serve man> for dinner.>')
mo.group()
'<To serve man> for dinner.>'
Correspondance des nouvelles lignes avec le caractère Point
Le point-étoile correspond à tout sauf une nouvelle ligne. En passant re.DOTALL comme deuxième argument à re.compile(), vous pouvez faire en sorte que le caractère point corresponde à tous les caractères, y compris le caractère de nouvelle ligne :
no_newline_regex = re.compile('.*')
no_newline_regex.search('Serve the public trust.\nProtect the innocent.\nUphold the law.').group()
'Serve the public trust.'
newline_regex = re.compile('.*', re.DOTALL)
newline_regex.search('Serve the public trust.\nProtect the innocent.\nUphold the law.').group()
'Serve the public trust.\nProtect the innocent.\nUphold the law.'
Correspondance insensible à la casse
Pour rendre votre regex insensible à la casse, vous pouvez passer re.IGNORECASE ou re.I comme deuxième argument à re.compile() :
robocop = re.compile(r'robocop', re.I)
robocop.search('Robocop is part man, part machine, all cop.').group()
'Robocop'
robocop.search('ROBOCOP protects the innocent.').group()
'ROBOCOP'
robocop.search('Al, why does your programming book talk about robocop so much?').group()
'robocop'
Substitution de chaînes avec la méthode sub()
La méthode sub() pour les objets Regex reçoit deux arguments :
- Le premier argument est une chaîne pour remplacer toutes les correspondances.
- Le second est la chaîne pour l’expression régulière.
La méthode sub() renvoie une chaîne avec les substitutions appliquées :
names_regex = re.compile(r'Agent \w+')
names_regex.sub('CENSORED', 'Agent Alice gave the secret documents to Agent Bob.')
'CENSORED gave the secret documents to CENSORED.'
Connectez-vous pour répondre à ce quiz et suivre votre progression d'apprentissage
sub() ?Gestion des Regex complexes
Pour indiquer à la fonction re.compile() d’ignorer les espaces et les commentaires à l’intérieur de la chaîne d’expression régulière, le “mode verbeux” peut être activé en passant la variable re.VERBOSE comme deuxième argument à re.compile().
Maintenant, au lieu d’une expression régulière difficile à lire comme celle-ci :
phone_regex = re.compile(r'((\d{3}|\(\d{3}\))?(\s|-|\.)?\d{3}(\s|-|\.)\d{4}(\s*(ext|x|ext.)\s*\d{2,5})?)')
vous pouvez répartir l’expression régulière sur plusieurs lignes avec des commentaires comme ceci :
phone_regex = re.compile(r'''(
(\d{3}|\(\d{3}\))? # indicatif régional
(\s|-|\.)? # séparateur
\d{3} # 3 premiers chiffres
(\s|-|\.) # séparateur
\d{4} # 4 derniers chiffres
(\s*(ext|x|ext.)\s*\d{2,5})? # extension
)''', re.VERBOSE)
Connectez-vous pour répondre à ce quiz et suivre votre progression d'apprentissage
re.VERBOSE lorsqu'il est passé à re.compile() ?