Nous vous proposons dans ce notebook quelques exercices sur les expressions régulières. Faisons quelques remarques avant de commencer :
nous nous concentrons sur l’écriture de l’expression régulière en elle-même, et pas sur l’utilisation de la bibliothèque ;
en particulier, tous les exercices font appel à
re.matchentre votre regexp et une liste de chaînes d’entrée qui servent de jeux de test.
Liens utiles¶
Pour travailler sur ces exercices, il pourra être profitable d’avoir sous la main :
et https://
regex101 .com/ (par exemple) qui permet de mettre au point de manière interactive, et donc d’avoir un retour presque immédiat, pour accélérer la mise au point.
Exercice - niveau intermédiaire (1)¶
Identificateurs Python¶
On vous demande d’écrire une expression régulière qui décrit les noms de variable en Python. Pour cet exercice on se concentre sur les caractères ASCII. On exclut donc les noms de variables qui pourraient contenir des caractères exotiques comme les caractères accentués ou autres lettres grecques.
Il s’agit donc de reconnaître toutes les chaînes qui commencent par une lettre ou un _, suivi de lettres, chiffres ou _.
# quelques exemples de résultat attendus
from corrections.regexp_pythonid import exo_pythonid
exo_pythonid.example()# à vous de jouer: écrivez ici
# sous forme de chaîne votre expression régulière
regexp_pythonid = r"votre_regexp"# évaluez cette cellule pour valider votre code
exo_pythonid.correction(regexp_pythonid)Exercice - niveau intermédiaire (2)¶
Lignes avec nom et prénom¶
On veut reconnaître dans un fichier toutes les lignes qui contiennent un nom et un prénom.
from corrections.regexp_agenda import exo_agenda
exo_agenda.example()The history saving thread hit an unexpected error (OperationalError('attempt to write a readonly database')).History will not be written to the database.
Plus précisément, on cherche les chaînes qui :
commencent par une suite - possiblement vide - de caractères alphanumériques (vous pouvez utiliser
\w) ou tiret haut (-) qui constitue le prénom ;contiennent ensuite comme séparateur le caractère ‘deux-points’
:;contiennent ensuite une suite - cette fois jamais vide - de caractères alphanumériques ou tiret haut, qui constitue le nom ;
et enfin contiennent un deuxième caractère
:mais optionnellement seulement.
On vous demande de construire une expression régulière qui définit les deux groupes nom et prenom, et qui rejette les lignes qui ne satisfont pas ces critères.
Dans la correction - et ce sera pareil pour tous les exercices de regexp où on demande des groupes - la correction affiche uniquement les groupes demandés; ici on va vous montrer les groupes nom et prenom; vous avez parfaitement le droit d’utiliser des groupes supplémentaires, nommés ou pas d’ailleurs, dans votre propre regexp.
# entrez votre regexp ici
# il faudra la faire terminer par \Z
# regardez ce qui se passe si vous ne le faites pas
regexp_agenda = r"votre regexp\Z"# évaluez cette cellule pour valider votre code
exo_agenda.correction(regexp_agenda)Exercice - niveau intermédiaire (3)¶
Numéros de téléphone¶
Cette fois on veut reconnaître des numéros de téléphone français, qui peuvent être :
soit au format contenant 10 chiffres dont le premier est un
0;soit un format international commençant par
+33suivie de 9 chiffres.
Dans tous les cas on veut trouver dans le groupe number les 9 chiffres vraiment significatifs, comme ceci :
from corrections.regexp_phone import exo_phone
exo_phone.example()# votre regexp
# à nouveau il faut terminer la regexp par \Z
regexp_phone = r"votre regexp\Z"# évaluez cette cellule pour valider votre code
exo_phone.correction(regexp_phone)Exercice - niveau avancé¶
Vu comment sont conçus les exercices, vous ne pouvez pas passer à re.compile un drapeau comme re.IGNORECASE ou autre ; sachez cependant que vous pouvez embarquer ces drapeaux dans la regexp elle-même ; par exemple pour rendre la regexp insensible à la casse de caractères, au lieu d’appeler re.compile avec le flag re.I, vous pouvez utiliser (?i) comme ceci :
import re# on peut embarquer les flags comme IGNORECASE
# directement dans la regexp
# c'est équivalent de faire ceci
re_obj = re.compile("abc", flags=re.IGNORECASE)
re_obj.match("ABC").group(0)'ABC'# ou cela
re.match("(?i)abc","ABC").group(0)'ABC'# les flags comme (?i) doivent apparaître
# en premier dans la regexp
re.match("abc(?i)","ABC").group(0)---------------------------------------------------------------------------
error Traceback (most recent call last)
Cell In[13], line 3
1 # les flags comme (?i) doivent apparaître
2 # en premier dans la regexp
----> 3 re.match("abc(?i)","ABC").group(0)
File /usr/lib/python3.12/re/__init__.py:167, in match(pattern, string, flags)
164 def match(pattern, string, flags=0):
165 """Try to apply the pattern at the start of the string, returning
166 a Match object, or None if no match was found."""
--> 167 return _compile(pattern, flags).match(string)
File /usr/lib/python3.12/re/__init__.py:307, in _compile(pattern, flags)
301 import warnings
302 warnings.warn("The re.TEMPLATE/re.T flag is deprecated "
303 "as it is an undocumented flag "
304 "without an obvious purpose. "
305 "Don't use it.",
306 DeprecationWarning)
--> 307 p = _compiler.compile(pattern, flags)
308 if flags & DEBUG:
309 return p
File /usr/lib/python3.12/re/_compiler.py:745, in compile(p, flags)
743 if isstring(p):
744 pattern = p
--> 745 p = _parser.parse(p, flags)
746 else:
747 pattern = None
File /usr/lib/python3.12/re/_parser.py:979, in parse(str, flags, state)
976 state.flags = flags
977 state.str = str
--> 979 p = _parse_sub(source, state, flags & SRE_FLAG_VERBOSE, 0)
980 p.state.flags = fix_flags(str, p.state.flags)
982 if source.next is not None:
File /usr/lib/python3.12/re/_parser.py:460, in _parse_sub(source, state, verbose, nested)
458 start = source.tell()
459 while True:
--> 460 itemsappend(_parse(source, state, verbose, nested + 1,
461 not nested and not items))
462 if not sourcematch("|"):
463 break
File /usr/lib/python3.12/re/_parser.py:840, in _parse(source, state, verbose, nested, first)
838 if flags is None: # global flags
839 if not first or subpattern:
--> 840 raise source.error('global flags not at the start '
841 'of the expression',
842 source.tell() - start)
843 verbose = state.flags & SRE_FLAG_VERBOSE
844 continue
error: global flags not at the start of the expression at position 3Pour plus de précisions sur ce trait, que nous avons laissé de côté dans le complément pour ne pas trop l’alourdir, voyez la documentation sur les expressions régulières et cherchez la première occurrence de iLmsux.
Décortiquer une URL¶
On vous demande d’écrire une expression régulière qui permette d’analyser des URLs.
Voici les conventions que nous avons adoptées pour l’exercice :
la chaîne contient les parties suivantes :
<protocol>://<location>/<path>;
l’URL commence par le nom d’un protocole qui doit être parmi
http,https,ftp,ssh;le nom du protocole peut contenir de manière indifférente des minuscules ou des majuscules ;
ensuite doit venir la séquence
://;ensuite on va trouver une chaîne
<location>qui contient :potentiellement un nom d’utilisateur, et s’il est présent, potentiellement un mot de passe ;
obligatoirement un nom de
hostname;potentiellement un numéro de port ;
lorsque les 4 parties sont présentes dans
<location>, cela se présente comme ceci :<location> = <user>:<password>@<hostname>:<port>;
si l’on note entre crochets les parties optionnelles, cela donne :
<location> = [<user>[:<password>]@]<hostname>[:<port>];
le champ
<user>ne peut contenir que des caractères alphanumériques ; si le@est présent le champ<user>ne peut pas être vide ;le champ
<password>peut contenir tout sauf un:et de même, si le:est présent le champ<password>ne peut pas être vide ;le champ
<hostname>peut contenir une suite non-vide de caractères alphanumériques, underscores, ou.;le champ
<port>ne contient que des chiffres, et il est non vide si le:est spécifié ;le champ
<path>peut être vide.
Enfin, vous devez définir les groupes proto, user, password, hostname, port et path qui sont utilisés pour vérifier votre résultat. Dans la case Résultat attendu, vous trouverez soit None si la regexp ne filtre pas l’intégralité de l’entrée, ou bien une liste ordonnée de tuples qui donnent la valeur de ces groupes ; vous n’avez rien à faire pour construire ces tuples, c’est l’exercice qui s’en occupe.
# exemples du résultat attendu
from corrections.regexp_url import exo_url
exo_url.example()# n'hésitez pas à construire votre regexp petit à petit
regexp_url = "votre_regexp"exo_url.correction(regexp_url)