Jul 03, 2024

Wiki

Python

Aide

edit SideBar

Search

La Methode Compile


Présentation

Pour l'instant, on ne sait que répondre à la question : « Le motif est-il présent ? »

On peut faire plus : savoir ce qui a été reconnu, et à quel endroit.

Pour illustrer cela, on considère le problème suivant (toujours tiré de Dive Into Python) : la reconnaissance de numéros de téléphone au États-Unis, à savoir déterminer

  • le code régional,
  • l'indicatif,
  • le numéro,
  • une extension optionnelle.

Voici les types de numéros de téléphone possibles :

  • 800-555-1212
  • 800 555 1212
  • 800.555.1212
  • (800) 555-1212
  • 1-800-555-1212
  • 800-555-1212-1234
  • 800-555-1212x1234
  • 800-555-1212 ext. 1234
  • work 1-(800) 555.1212 #1234

Dans ce qui précède, le code régional à reconnaître est 800, l'indicatif 555 et le reste du numéro 1212. L'extension, pas toujours présente, est 1234.

Création du motif

Pour réaliser ce motif, on va utiliser :

  • \d, qui signifie «un chiffre»,
  • {3}, pour «exactement trois fois ce qui précède» : \d{3} signifie donc un nombre de 3 chiffres.
  • les parenthèses autour de \d{3}, pour signifier que chaque sous-motif de trois chiffres doit être considéré comme un groupe à part, qui sera plus tard exploité.

Ce qui donne le motif suivant :

r'^(\d{3})-(\d{3})-(\d{4})\$'

Première utilisation de compile

Pour en faire une utilisation avancée, il faut commencer par compiler l'expression rationnelle :

  >>> import re
  >>> motif_tel = re.compile(r'^(\d{3})-(\d{3})-(\d{4})$')

Cela crée un objet motif (sre.SRE_Pattern) :

  >>> motif_tel
  <_sre.SRE_Pattern object at 0x1f7cb80>

Cet objet possède une méthode search :

  >>> motif_tel.search('800-555-1212')
  <_sre.SRE_Match object at 0x7f49f2d531f8>
  >>> motif_tel.search('800-555-1212-1234')
  >>> 

Dans ce qui précède, le motif motif_tel est donc recherché (search) dans la chaine passée en argument de search.

En fait, le motif est réellement compilé en du bytecode (C), qui permettra une recherche efficace.

Les groupes

On souhaite obtenir des résultats concrets avec cette recherche : le code régional, l'indicatif et le numéro.

Ces résultats correspondent respectivement à chacun des trois groupes (\d{3}). On rappelle que les parenthèses sont justement présentes pour les identifier en tant que groupe.

On peut alors passer la méthode groups() à l'objet considéré, résultat de search :

  >>> motif_tel = re.compile(r'^(\d{3})-(\d{3})-(\d{4})$')
  >>> motif_tel.search('800-555-1212').groups()
  ('800', '555', '1212')

Cas de l'extension optionnelle

On traite maintenant l'extension optionnelle : un quatrième groupe de chiffres, éventuellement présent dans le numéro de téléphone.

Ce groupe optionnel est constitué d'un nombre quelconque, mais non nul, de chiffres.

On peut obtenir cela avec +. Ainsi, \d+ signifie «un nombre quelconque, mais non nul, de chiffres».

  >>> motif_tel = re.compile(r'^(\d{3})-(\d{3})-(\d{4})-(\d+)$')
  >>> motif_tel.search('800-555-1212-1234').groups()
 ('800', '555', '1212', '1234') 

Cependant, avec cette solution, on ne peut plus reconnaître les numéros de téléphones sans extension, ni ceux comprenant un autre séparateur que - :

  >>> motif_tel.search('800-555-1212')
  >>> motif_tel.search('800 555 1212 1234')
  >>> 

Amélioration du motif

On va considérer qu'un séparateur est un nombre quelconque, non nul, de symboles qui ne sont pas des chiffres.

Pour cela, on utilise \D, qui signifie : « Tout caractère qui n'est pas un chiffre. »

  >>> motif_tel = re.compile(r'^(\d{3})\D+(\d{3})\D+(\d{4})\D+(\d+)$')
  >>> motif_tel.search('800 555 1212 1234').groups()
  ('800', '555', '1212', '1234')
  >>> motif_tel.search('800-555-1212-1234').groups()
  ('800', '555', '1212', '1234')

Seulement, il se peut qu'aucun séparateur ne soit utilisé. Auquel cas, notre motif ne marche pas.

  >>> motif_tel.search('80055512121234')
  >>> 

Pour se faire, on va remplacer \D+ par \D*, car * signifie : « Un nombre quelconque, éventuellement nul ».

  >>> motif_tel = re.compile(r'^(\d{3})\D*(\d{3})\D*(\d{4})\D*(\d*)$')
  >>> motif_tel.search('80055512121234').groups()
  ('800', '555', '1212', '1234')
  >>> motif_tel.search('800.555.1212 x1234').groups()
  ('800', '555', '1212', '1234')
  >>> motif_tel.search('800-555-1212').groups()
  ('800', '555', '1212', '')

On peut encore raffiner la reconnaissance du motif : certains codes régionaux sont entourés de parenthèse, et notre motif ne permet pas de gérer cela...

  >>> phonePattern.search('(800)5551212 x1234')
  >>> 
  >>> phonePattern = re.compile(r'^\D*(\d{3})\D*(\d{3})\D*(\d{4})\D*(\d*)$')
  >>> phonePattern.search('(800)5551212 ext. 1234').groups()
  ('800', '555', '1212', '1234')

Un dernier problème

Il reste un dernier cas de figure, que notre motif ne reconnait pas :

  >>> motif_tel.search('work 1-(800) 555.1212 #1234')
  >>> 

Cela vient du fait que \D signifie « Tout caractère non numérique » alors que work 1- contient un chiffre.

En fait, ce qui précède le premier groupe de 3 chiffres peut être de taille quelconque, et contenir des chiffres.

Pour solutionner ce problème, il suffit d'enlever tout ce qui précède le premier groupe de chiffres à reconnaître, ^ y compris. Au lieu d'essayer d'identifier ces éléments gênants, pour les sauter, on les ignore simplement...

  >>> motif_tel = re.compile(r'(\d{3})\D*(\d{3})\D*(\d{4})\D*(\d*)$')
  >>> motif_tel.search('work 1-(800) 555.1212 #1234').groups()
  ('800', '555', '1212', '1234')
  >>> motif_tel.search('800-555-1212')
  ('800', '555', '1212', '')
  >>> motif_tel.search('80055512121234')
  ('800', '555', '1212', '1234')

L'expression régulière détaillée

On écrit tout cela à l'aide d'une expression plus lisible :

  >>> motif_tel = re.compile(r'''
  ...               # On ne vérifie pas si l'on est en début de chaîne
  ...   (\d{3})     # Code régional de trois chiffres
  ...   \D*         # Séparateur optionnel
  ...   (\d{3})     # L'indicatif de 3 chiffres
  ...   \D*         # Séparateur optionnel
  ...   (\d{4})     # Le numéro (4 chiffres)
  ...   \D*         # Séparateur optionnel
  ...   (\d*)       # Extension optionnelle (un nombre quelconque)
  ...   $           # Fin de la chaîne
  ...  ''', re.VERBOSE)
  ...
  >>> motif_tel.search('work 1-(800) 555.1212 #1234').groups()
  ('800', '555', '1212', '1234')
  >>> motif_tel.search('800-555-1212')
  ('800', '555', '1212', '')

Travaux pratiques

Récupérer des liens Rapidshare

Supposons que vous souhaitiez récupérer une image ISO d'un DVD d'une distribution Debian GNU/Linux.

Vous avez trouvé un site qui centralise des liens vers rapidshare, contenant ladite distribution. Seulement, au lieu d'un lien, vous en avez plusieurs dizaines : l'image ISO a été découpée en parties de 100 Mo.

Vous souhaitez récupérer ces liens, et faire un script qui lancera le téléchargement de ces liens l'un après l'autre. Pour ce faire, vous sauvegardez le fichier html, et il vous faut récupérer tous les liens de la forme http://www.rapidshare.com/....

Faire un programme Python qui ouvre un fichier texte, et qui récupère dedans tous les liens rapidshare.

Les informations des CVs

J'ai eu à visiter un stagiaire d'IUT travaillant au sein d'une boîte de ressources humaines. Des personnes en recherche d'emploi s'inscrivaient sur le site de la boîte, et pouvaient déposer leurs CVs sous la forme de document Word,etc.

La tâche de l'étudiant était de récupérer automatiquement le plus d'informations possibles (adresse, téléphone) dans ces CVs, afin de réduire le temps de saisie (du document Word vers la base de données).

  1. Faire, sur le même principe, un script qui permet de relever les numéros de téléphone dans un CV.
  2. Étendre cela aux adresses : rues, codes postaux, villes.

On pourra parcourir quelques CVs sur internet, pour envisager les différents cas possibles.

Page Actions

Recent Changes

Group & Page

Back Links