Regex Python
Regex Python
introduction.
Avant d'aborder le module des expressions rgulires, on va examiner quelques mthodes relatives
aux chanes de caractres ou qui leur sont apparentes.
1. Poser le problme.
Problme : On dispose d'un texte, c'est dire pour Python d'une chane de caractres ; par ailleurs,
on propose un motif, qui est lui aussi une chane de caractres. Le problme consiste dtecter la
prsence du motif dans le texte, et ventuellement de remplacer ce motif par un autre..
Le texte se prsente sous forme d'une chane de caractres en mmoire vive (variable, chane
littrale) ; on ne se pose pas de problme d'encodage (UNICODE) puisque l'on ne cherche pas
transformer la chane en tableau binaire. Attention cependant, si on dispose d'un fichier de texte, le
problme de l'encodage se pose lors du chargement (voir la fiche sur les fichiers de texte en Python) !
Le motif est une chane sans problme particulier : les sauts de lignes sont cods \n, l'antislash est
cod \\. L'antislash protge les quotes contenues dans la chane. Il n'y a pas d'autre utilisation de
l'antislash.
rappel : un antislash en fin de ligne annule la fin de ligne. Il permet par exemple, d'crire une chane
de caractres un peu longue sur plusieurs lignes physiques.
2. Trouver.
2.1. ce que dit la documentation.
#!/usr/bin/python3
# rechercher dans une chane
texte = "Un IDE ou \"environnement de dveloppement\" est un logiciel \
constitu d'outils qui facilitent l'criture et les tests dans un \
langage dfini, voire plusieurs.\
\nCet IDE comporte en gnral un diteur avec coloration syntaxique,\
un systme de gestion de fichiers (sauvegarde/chargement),\
un compilateur, un excuteur de programme, un systme d'aide en ligne,\
des indicateurs de syntaxe etc. \
\nLe plus connu est peut tre clipse."
rsultat :
>>>
premire occurrence du motif : 3
nombre d'occurrences du motif : 2
clipse est prsent comme clipse
>>>
3. Remplacer.
3.1. ce que dit la documentation.
str.replace(old, new[, count])
retourne une copie de la chane o toutes les occurrences de la sous-chane old sont
remplaces par la chane new. Si la valeur count est prcise, seules les count premires
occurrences sont remplaces.
3.2. un exemple.
#!/usr/bin/python3
# remplacer dans une chane
texte = "Un IDE ou \"environnement de dveloppement\" est un logiciel \
rsultat :
>>>
Un IDE ou "environnement de dveloppement" est un logiciel constitu
d'outils qui facilitent l'criture et les tests dans un langage dfini,
voire plusieurs. Cet IDE comporte en gnral un diteur avec coloration
syntaxique,un systme de gestion de fichiers (sauvegarde/chargement),un
compilateur, un excuteur de programme, un systme d'aide en ligne,des
indicateurs de syntaxe etc. Le plus connu est peut tre clipse.
>>>
4. Dcouper.
4.1. ce que dit la documentation.
str.split([sep[, maxsplit]])
retourne une liste de mots de la chane, en utilisant sep comme dlimiteur. Si maxsplit est
donn, il y a au plus maxsplit coupures (et la liste a au plus maxsplit+1 lments).
En l'absence de sparateur spcifi, ou avec le sparateur None, l'espace est considr
comme sparateur.
str.splitlines([keepends])
retourne une liste des lignes de la chane. En principe, le sparateur de ligne n'est pas gard,
sauf si keepend est pos True.
4.2. exemples.
#!/usr/bin/python3
# couper une chane
texte = "123,,456,"
# split
liste = texte.split (",")
print ("texte :",texte, "\nliste :", liste,"\n\n")
# splitline
texte = "\nABC\nDEF\nGHI"
liste = texte.splitlines()
print ("texte :",texte, "\nliste :", liste,"\n\n")
rsultats :
>>>
texte : 123,,456,
liste : ['123', '', '456', '']
texte :
ABC
DEF
GHI
liste : ['', 'ABC', 'DEF', 'GHI']
texte :
ABC
DEF
GHI
liste : ['\n', 'ABC\n', 'DEF\n', 'GHI']
>>>
introduction
Les expressions rgulires en Python 3 peuvent tre abordes l'aide du module re :
import re # module des expressions rgulires
Les fichiers du module re.py, re.pyc, re.pyo, respectivement le fichier source, le fichier
compil, le fichier optimis se trouvent dans le rpertoire des librairies Lib, la racine. Il n'y a donc
aucun problme particulier pour son utilisation. C'est l que la machine Python cherche les modules
(aprs le rpertoire actuel, videmment).
Dans les fiches qui suivent, on utilise l'importation sous la forme import ; il faut donc qualifier
systmatiquement les lments constitutifs du module. En production, il se peut qu'il soit intressant,
pour viter des lourdeurs de code, d'utiliser la forme from... import et de dfinir des alias. C'est
videmment tout fait possible, mais ce n'est pas ici le lieu d'en discuter.
1. Matching et Searching.
1.1. vocabulaire.
Pour la clart de l'expos, nous traduirons le verbe to match par correspondre , et to search
par rechercher et donc matching par correspondance et searching par recherche. Il ne
faut pas chercher de signification "intuitive" ces concepts qui ont dans chacun des langages comme
C, Java ou Python un sens prcis, mais malheureusement pas le mme d'un langage l'autre.
1.2. poser le problme.
Problme : On dispose d'un texte, c'est dire pour Python une chane de caractres ; par ailleurs, on
propose un patron (ou motif), qui est lui aussi une chane de caractres. Le problme consiste
dtecter une sous-chane respectant le patron dans le texte et ventuellement remplacer par une
chane prdfinie la (ou les) sous-chanes(s) trouves. D'autres oprations sont possibles, qui seront
vues en leur temps.
Le texte se prsente sous forme d'une chane de caractres en mmoire vive (variable, chane
littrale) ; on ne se pose pas de problme d'encodage (UNICODE par dfaut en version 3 ; en
versions 2.x, le code est le code local. On peut dfinir la norme de l'encodage par une clause
-code-). Si on dispose d'un fichier de texte, le problme de l'encodage se pose lors du chargement !
Le patron est pour l'instant une chane, avec quelques problmes : comme d'habitude, les sauts de
lignes sont cods \n, l'antislash est cod \\. L'antislash protge les quotes. Mais il doit aussi protger
un certain nombre de caractres usuels comme le point, ^, $, + , ?, * . Cela sera explicit plus
compltement dans les fiches qui suivent.
Les directives se prsentent sous forme d'un entier : chaque directive est une puissance de deux,
et le paramtre directives est la somme de directives particulires.
#!/usr/bin/python3
import re
note. Il existe plusieurs prsentations syntaxiques pour les mthodes comme search(). Dans le
script ci-dessus, search() est une mthode de l'objet SRE_Pattern. Mais Python l'a galement
redfini comme une fonction du module re :
exemple : re.search(patron, texte, re.IGNORECASE))...
Pour la clart de l'expos, on s'en tient une seule syntaxe, celle du script ci-dessus, qui a l'avantage
de ressembler ce qui se fait en java.
2. Expression rgulire.
2.1. remarques sur la section prcdente.
La section qui prcde a pour objectif de spcifier une syntaxe : celle requise par le module re pour
faire des oprations assez semblables celles ralises avec plus de simplicit par les mthodes de
la classe str.
Quel est l'apport du module re pour les oprations de recherche, de comparaison, de substitution, de
dcoupage de chanes ? Lorsque l'on fait une recherche ou une substitution dans un traitement de
texte ou un diteur, la chane recherche doit tre explicite. On peut imposer de ne pas diffrencier
majuscules et minuscules, ou de ne rechercher que des mots entiers ; ces amnagements sont
insuffisants.
note : les diteurs et traitements de texte actuels peuvent travailler diffremment !
On peut souhaiter disposer, pour crire les patrons, de jokers (comme le * ou le ? dans les shells des
. le point remplace tout caractre sauf le sous DOTALL, le point reprsente tout
saut de ligne (\n). caractre, y compris le saut de ligne.
itrateur interprtation
* zro, une ou plusieurs fois le caractre qui prcde
+ une ou plusieurs fois le caractre qui prcde
? zro ou une fois le caractre qui prcde
{m} exactement m fois le caractre qui prcde
{m,} au moins m fois le caractre qui prcde
{m,n} au moins m fois et au plus n fois le caractre qui prcde
exemples :
2.4. consommation.
Lorsqu'une recherche est couronne de succs, la partie de la chane comprise entre le dbut de
celle-ci et la fin de la sous-chane trouve est consomme. Ce qui signifie par exemple que la fonction
findall() commence la recherche partir du caractre suivant le dernier caractre consomm. La
recherche est squentielle et elle ne fait aucun retour en arrire.
2.5. gourmandise.
les itrateurs *, +, ? sont gourmands. C'est--dire que dans une recherche, ils ont un
comportement qui conduit reconnatre la plus grande chane possible. Ils consomment la chane au
maximum, mme si une correspondance a dj t trouve sur le patron propos.
Par exemple, supposons que l'on ait :
texte = "<h1>Expressions Rgulires</h1>"
patron = "<.*>"
Le sous-motif .* conduit avoir le plus grand texte possible : l'expression rgulire s'identifie tout le
texte. Il faut lire patron comme :
le caractre < pour commencer ; un maximum de caractres ; le caractre > pour finir.
On aurait pu souhaiter au contraire une identification <h1>, c'est--dire :
le caractre < pour commencer ; un minimum de caractres ; le caractre >.
Une nouvelle classe d'itrateurs ralisent ces oprations :
itrateur interprtation
*? zro, une ou plusieurs fois le caractre qui prcde ; non gourmand. Dans une
expression, *? s'identifie la plus petite chane possible.
+? une ou plusieurs fois le caractre qui prcde ; non gourmand.
?? zro ou une fois le caractre qui prcde ; non gourmand.
{m,n}? le caractre qui prcde m fois.
exemple :
import re
texte = "<<aaAAabbbccaaannn"
patron = "a{2,3}b?"
cpatron = re.compile(patron, re.I)
res = cpatron.findall(texte)
print ("patron :",patron,"rsultat : ",res)
patron = "a{2,3}?b?"
cpatron = re.compile(patron, re.I)
patron = "a{2,3}b??"
cpatron = re.compile(patron, re.I)
res = cpatron.findall(texte)
print ("patron :",patron,"rsultat : ",res)
rsultat :
>>>
patron : a{2,3}b? rsultat : ['aaA', 'Aab', 'aaa']
patron : a{2,3}?b? rsultat : ['aa', 'AA', 'aa']
patron : a{2,3}b?? rsultat : ['aaA', 'Aa', 'aaa']
>>>
2.5. chappement.
Les jokers et les oprateurs sont des caractres courants. Comment, dans une expression rgulire
peut-on distinguer ce caractre en tant que caractre et le mme en tant qu'oprateur ou composant
d'un oprateur ? On utilise le mme systme que Python dans ce cas : pour considrer un caractre
comme se reprsentant lui-mme, il faut l'chapper par un antislash. On aura donc pour le point \.,
pour l'astrisque \*, pour le signe plus \+ et ainsi de suite. Cela peut se compliquer ; un chapitre
spcial sera consacr cette question.
Ablon non
Acqueville oui
Agy non
Aigner-Ville oui / majuscules
Airan non
Amay-sur-Orne non
Amblie non
Amfreville oui
Angervillers non / ville non terminal
Angoville oui
le source :
#!/usr/bin/python3
import re
texte ="Ablon\nAcqueville\nAgy\nAigner-Ville\nAiran\nAmay-sur-Orne\
\nAmblie\nAmfreville\nAngervillers\nAngoville\nArganchy\nArgences\
\nArromanches-les-Bains\nAsnelles\nAsnires-Surville"
patron = ".*ville$"
cpatron = re.compile (patron)
resultat = cpatron.findall(texte)
print (resultat, "\n")
".*ville$" : une suite gourmande de caractres, suivie de ville, suivie de la fin de texte.
Les fins de chane ne sont pas incluses. Seule la dernire ligne peut tre prise en compte si on ne
met pas de directives !
rsultats :
>>>
['Asnires-Surville']
>>>
#!/usr/bin/python3
# substitution dans une chane
import re
rsultat :
>>>
Retourne le texte avec ses remplacements
************************************
>>>
['Ablon\nAcqueville\nAgy\nAigner-Ville\nAiran\nAmay-sur-
Orne\nAmblie\nAmfreville\nAngervillers\nAngoville\nArganchy\nArgences\n
Arromanches-les-Bains\nAsnelles\n', '']
['Ablon\n', '\nAgy\nAigner-Ville\nAiran\nAmay-sur-Orne\nAmblie\n',
'\nAngervillers\n', '\nArganchy\nArgences\nArromanches-les-
Bains\nAsnelles\n', '']
>>>
introduction.
Les oprateurs vus dans la fiche qui prcde permettent de rpondre aux problmes lis la
rptition d'un caractre. Le seul joker dont on dispose est le point (sous deux acceptions, avec ou
sans fin de ligne). La premire extension souhaitable est de diversifier les jokers.
2. Parenthsage.
2.1. analogie mathmatique.
En calcul numrique, on utilise les parenthses pour hirarchiser les oprations. Il en est de mme
pour les expressions rgulires. On peut parenthser une sous-expression rgulire et lui appliquer
les oprateurs d'itration vus pour les caractres.
ATTENTION !
Le parenthsage a une syntaxe peu intuitive et droutante :
(?:expression rgulire)
2.2. un exemple.
problme : examiner si une chane est une adresse mail valide. Une adresse mail comporte une ou
deux chanes alphanumriques ; dans ce second cas, un point les spare. Le caractre @ suit. La
seconde partie est constitue d'une suite d'au moins deux chanes alphanumriques spares par un
point.
#!/usr/bin/python3
import re
textes1 = ['[email protected]', "[email protected]",
"[email protected]",'zorlubfree.fr']
textes2 = ['zorlub@free', "[email protected]",
"[email protected]. fr","[email protected] "]
>>>
[email protected] est correct
[email protected] est correct
[email protected] n'est pas une adresse valide
zorlubfree.fr n'est pas une adresse valide
zorlub@free n'est pas une adresse valide
[email protected] est correct
Un analyseur lexical prend un flot de caractres sur son entre standard, isole les units lexicales, et
envoie un flot d'units lexicales sur sa sortie standard. Une unit lexicale peut tre un identificateur,
un mot rserv du langage, un signe (+ - * / ! etc), un dlimiteur (parenthse, accolade, crochet, /*,
*/ etc), c'est--dire toute unit pertinente pour l'analyse syntaxique.
quelque cas :
La chane "\123" donne le caractre de code octal 123 en Unicode, soit S (code 64+2x8+3 = 83) :
print (ord("\123"), "123")
La chane "\u00b5" donne le de code 181 :
print (ord("\u00b5"), "\u00b5")
Chaque caractre unicode a un nom (importer le module unicode):
print (ord("\u00b5"), "\u00b5", unicodedata.name("\u00b5"))
donne : 181 MICRO SIGN
D'o la liste des caractres alphanumriques pour lesquelles l'antislash n'est pas un littral
#!/usr/bin/python3
import re
textes = "[email protected],[email protected],[email protected],\
[email protected],[email protected],[email protected]"
patron = "\\b\
\w+\
(?:[.]\w+)?\
@\
\w+\
(?:[.]\w+)*\
[.](?:fr|com)\
\\b"
print (patron,"\n")
cpatron = re.compile(patron)
print (cpatron.findall(textes))
>>>
\b\w+(?:[.]\w+)?@\w+(?:[.]\w+)*[.](?:fr|com)\b
exemple :
#!/usr/bin/python3
import re
textes = "[email protected],[email protected],[email protected],\
[email protected],[email protected],[email protected]"
cpatron = re.compile(patron)
print (cpatron.findall(textes))
donne :
>>
\b(?# d> but de mot)\w+(?:[.]\w+)?(?# un ou deux mots spars par
un point)@\w+(?:[.]\w+)*(?# un, ou plusieurs mots spars
par un point)[.](?:fr|com)(?# le dernier tant soit fr soit com)
\b(?# fin de mot)
* On a ici combin les deux mthodes : le gain de lisibilit est rel mais ce n'est pas encore le grand
confort : il manque une aration par des espaces par exemple. D'autre part, la mthode de l'antislash
terminal peut introduire des erreurs peu visibles si on ajoute malencontreusement des blancs.
4.3. la directive VERBOSE.
La directive VERBOSE a comme effet d'occulter tous les blancs (espaces, tabulations, fin de ligne...) de
la chane de saisie. De plus, l'introduction dans une ligne du symbole # a le mme effet qu'en Python :
il supprime la fin de ligne physique partir du dise. Encore faut-il qu'il y ait fin de ligne ! La triple
quote s'impose alors ; la chane dlimite ainsi est prise littralement, avec ses fins de lignes.
On dispose de l'aration souhaite, mais au prix d'une perte des blancs et du dise. Il suffit en gnral
d'utiliser le joker\s pour rsoudre le problme, ou alors de protger le caractre dans une classe ou
avec un antislash.
exemple.
#!/usr/bin/python3
import re
textes = "[email protected],[email protected],[email protected],\
[email protected],[email protected],[email protected]"
patron = """
\\b # dbut de mot)
\w+(?:[.]\w+)? # un ou deux mots spars par un point
@\
\w+(?:[.]\w+)* # un, ou plusieurs mots mots spars par un point
[.]\
print (cpatron.findall(textes))
>>>
\b # dbut de mot)
\w+(?:[.]\w+)? # un ou deux mots spars par un point
@ \w+(?:[.]\w+)* # un, ou plusieurs mots mots spars par un
point
[.] (?:fr|com) # le dernier tant soit fr soit com
\b # fin de mot
#!/usr/bin/python3
import re
cpatron = re.compile(
"\\b" # dbut de mot
"\w+" # suite de caractres alphamriques
"(?:[.]\w+)?" # 0 ou 1 point et suite de caractres alphanumriques
"@" #
"\w+" # suite de caractres alphamriques
"(?:[.]\w+)*" # x point et suite de caractres alphanumriques
"[.](?:fr|com)" # suffixe en fr ou en com
"\\b" # fin de mot
)
print (cpatron.findall(textes))
On joue ici triplement sur l'implicite : dans une parenthse, les nouvelles lignes ne sont pas prises en
compte ; les commentaires sont ignors l'analyse lexicale ; deux chanes littrales juxtaposes sont
concatnes... Cela fonctionne, mais c'est dangereux !
4.5. l'oprateur de chane r.
Il existe un oprateur de chane, r, qui permet de court-circuiter l'analyse lexicale de Python. Il suffit
#!/usr/bin/python3
import re
textes = "[email protected],[email protected],[email protected],\
[email protected],[email protected],[email protected]"
patron = r"\b\w+(?:[.]\w+)?@\w+(?:[.]\w+)*[.](?:fr|com)\b"
cpatron = re.compile(patron)
print (cpatron.findall(textes))
#!/usr/bin/python3
import re
texte ="Ablon\nAcqueville\nAgy\nAigner-Ville\nAiran\nAmaville-sur-Ville\
\nAmblie\nTrouville\nAngervillers\nAngoville\nArganchy\
\nAsnelles\nAsnires-Surville\nVille\nVilleneuve"
#!/usr/bin/python3
import re
textes = ["[email protected]","[email protected]","[email protected]",
"[email protected]", "[email protected]" ]
patron = "^\w+(?:[.]\w+)?@\w+(?:[.]\w+)*[.](?:fr|com)$"
cpatron = re.compile(patron)
for x in textes:
res = cpatron.search(x)
if res:
print (x)
>>>
[email protected]
[email protected]
[email protected]
>>>
#!/usr/bin/python3
import re
textes = "[email protected],[email protected],[email protected],\
[email protected],[email protected]"
patron = "\\b\w+(?:[.]\w+)?@\w+(?:[.]\w+)*[.](?:fr|com)\\b"
cpatron = re.compile(patron)
introduction.
On a dj rencontr un mode de groupement : le "parenthsage" ; il existe un second systme appel
groupe, qui a, en plus des proprits du parenthsage, des proprits trs spcifiques. On prendra
garde que le "groupe" n'est pas l'quivalent du parenthsage mathmatique.
1. Les groupes.
1.1. groupement de sous-expressions rgulires.
Un patron est un groupe ; c'est le groupe de niveau le plus bas, le niveau 0. Si on veut dfinir des
sous-groupes, il suffit de parenthser des sous-expressions rgulires constituant l'expression
globale. Les groupes sont numrots : 0 pour le patron, 1, 2,... pour les sous-groupes. La
numrotation se fait de gauche droite, et pour un groupe, elle est gale au nombre total de
parenthses ouvrantes qui le prcde.
On rcupre les groupes en analysant l'objet SRE_Pattern retourn par search() ; quant la
mthode findall() elle retourne une liste groupes ou de tuples (n-uplets) de groupes (voir
exemple ci-dessous).
note. Les littraux ( et ) doivent tre protgs. Mais attention ! Le point d'interrogation ne peut
suivre la parenthse ouvrante ; il faut aussi le protger : (? se code \(\?.
Les oprateurs comme *, +, ?, |, qui s'appliquent un caractre ou une expression paranthse
s'appliquent un groupe.
1.2. exemples avec search().
exemple 1.
#!/usr/bin/python3
import re
texte ="Ablon\nAcqueville\nAgy\nAigner-Ville\nAiran\nAmay-sur-Orne\
\nAmblie\nAmfreville\nAngervillers\nAngoville\nArganchy\nArgences\
\nArromanches-les-Bains\nAsnelles\nAsnires-Surville"
patron = "(.*)ville$"
cpatron = re.compile (patron,re.MULTILINE)
resultat = cpatron.search(texte)
print (resultat.start(0),resultat.end(0), resultat.group(0))
print (resultat.start(1),resultat.end(1), resultat.group(1))
>>>
6 16 Acqueville
6 11 Acque
>>>
exemple 2.
#!/usr/bin/python3
import re
texte ="Ablon\nAcqueville\nAgy\nAigner-Ville\nAiran\nAmay-sur-Orne\
\nAmblie\nAmfreville\nAngervillers\nAngoville\nArganchy\nArgences\
patron = "(.*)(vi\w*)$"
cpatron = re.compile (patron,re.MULTILINE)
resultat = cpatron.search(texte)
print (resultat.start(0),resultat.end(0), resultat.group(0))
print (resultat.start(1),resultat.end(1), resultat.group(1))
print (resultat.start(2),resultat.end(2), resultat.group(2))
>>>
6 16 Acqueville
6 11 Acque
11 16 ville
>>>
exemple 1.
#!/usr/bin/python3
import re
texte ="Ablon\nAcqueville\nAgy\nAigner-Ville\nAiran\nAmay-sur-Orne\
\nAmblie\nAmfreville\nAngervillers\nAngoville\nArganchy\nArgences\
\nArromanches-les-Bains\nAsnelles\nAsnires-Surville"
patron = "(.*)vi\w*$"
cpatron = re.compile (patron, re.MULTILINE)
resultat = cpatron.findall(texte)
print (resultat)
>>>
['Acque', 'Amfre', 'Anger', 'Ango', 'Asnires-Sur']
>>>
patron = "(.*)(vi\w*)$"
cpatron = re.compile (patron, re.MULTILINE+re.IGNORECASE)
resultat = cpatron.findall(texte)
print (resultat)
>>>
[('Acque', 'ville'), ('Aigner-', 'Ville'), ('Amfre', 'ville'),
('Anger', 'villers'), ('Ango', 'ville'), ('Asnires-Sur', 'ville')]
>>>
#!/usr/bin/python3
import re
texte ="Ablon\nAcqueville\nAgy\nAigner-Ville\nAiran\nAmaville-sur-Ville\
\nAmblie\nTrouville\nAngervillers\nAngoville\nArganchy\
\nAsnelles\nAsnires-Surville\nVille\nVilleneuve"
patron = "(^.*ville-.*)|(^.*ville$)"
cpatron = re.compile (patron,re.MULTILINE+re.IGNORECASE)
resultat = cpatron.findall(texte)
print (resultat)
>>>
[('', 'Acqueville'), ('', 'Aigner-Ville'), ('Amaville-sur-Ville', ''),
('', 'Trouville'), ('', 'Angoville'), ('', 'Asnires-Surville'), ('',
'Ville')]
>>>
#!/usr/bin/python3
import re
texte = " abcdefghijklmnopqrstuvwxyz "
patron = "abc(def(ghi)(jkl))(mno)pqr"
cpatron = re.compile(patron)
res = cpatron.search(texte)
if res :
try:
for i in range (99) : # maximum de 99 groupes
print ("groupe", i , ":", res.group(i))
except:
pass
>>>
groupe 0 : abcdefghijklmnopqr
groupe 1 : defghijkl
groupe 2 : ghi
groupe 3 : jkl
groupe 4 : mno
>>>
#!/usr/bin/python3
import re
texte = " abcdefghijklmnopqrstuvwxyz "
patron = "abc(?P<gr1>def(?P<gr2>ghi)(?P<gr3>jkl))(?P<gr4>mno)pqr"
cpatron = re.compile(patron)
res = cpatron.search(texte)
if res :
for i in range (1, 99) :
try :
print ("groupe "+str(i), res.group("gr"+str(i)))
except :
pass
donne :
>>>
groupe 1 defghijkl
groupe 2 ghi
groupe 3 jkl
groupe 4 mno
>>>
#!/usr/bin/python3
import re
patron = "\\b(\w).*?\\1\\b"
cpatron = re.compile(patron)
while True :
print (texte)
res = cpatron.search(texte)
if res :
print (res.group(0))
texte = texte [res.end():]
else:
break
donne :
>>>
J'ai t en sursis et j'irai bien dsormais
t
en sursis et j'irai bien dsormais
sursis
et j'irai bien dsormais
irai
bien dsormais
>>>
#!/usr/bin/python3
import re
patron = "\\b(?P<premiereLettre>\w)\w*(?P=premiereLettre)\\b"
cpatron = re.compile(patron)
while True :
res = cpatron.search(texte)
if res :
print (res.group(0))
texte = texte [res.end():]
else:
break
donne :
>>>
t
sursis
irai
>>>
import re
patron = """
(<h\d|<p) # balise commenant par <h avec chiffre ou <p
.*? # suite non gourmande de caractres
align\s*=\s*center # suivie du motif recherch
.*? # suite non gourmande de caractres
(>) # termine par >
"""
# le patron comporte deux groupes
print (res)
>>>
[('<h1', '>'), ('<p', '>'), ('<h2', '>')]
1. Lookahead.
1.1. lookahead positif ou ngatif.
le problme :
Supposons que l'on dispose de l'expression rgulire patron mais que l'on veuille chercher une
correspondance conditionnelle : seulement si l'expression trouver est "suivie" (ou n'est pas suivie)
d'une expression trouve avec une autre expression rgulire hpatron.
Par exemple on cherche la chane "Isaac" suivie par "Newton" ou "Asimov". Ou le contraire.
videmment, on peut compliquer un peu.
Une telle recherche s'appelle un lookahead. Sa caractristique essentielle est qu'elle ne consomme
que la chane recherche, pas la chane conditionnelle.
La syntaxe est la suivante :
(?=expression lookahead recherche)
(?!expression lookehaed rejete)
patron ="Isaac(?:\s|$)(?!Asimov|Newton)"
cpatron = re.compile(patron, re.IGNORECASE)
print (cpatron.findall(texte))
>>>
['Isaac ', 'Isaac ']
['isaac ', 'isaac ', 'isaac\n', 'isaac ', 'Isaac']
>>>
* rappel \s pour un blanc (espace, fin de ligne).
* on voit bien sur le second cas qu'il n'y a pas consommation du lookahead.
#!/usr/bin/python3
import re
texte = "isaac jacob, IsaacNewton, Isaac Asimov, bellisaac"
patron ="(?=\\bisa\w*\\b)isaac"
cpatron = re.compile(patron, re.IGNORECASE)
2. Lookbehind.
2.1. lookbehind positif ou ngatif.
Une recherche de correspondance avec comme condition de suivre (ou non) une correspondance
dfinie par une autre expression rgulire est un lookbehind. Le lookbehind consomme l'expression
prcdente, mais ne la retourne pas. Il n'y a pas de chevauchement avec le lookbehind, car la chane
conditionnelle est avant la chane recherch.
Restriction : l'expression qui sert de condition doit avoir une longueur prfixe ; on ne peut
avoir de .* ou \w* ; mais on peut avoir toto|papa. Sinon, Il y a erreur la compilation.
syntaxe :
(?<=expression lookbehind recherche)
(?<!expression lookbehind rejete)
#!/usr/bin/python3
import re
texte = "isaac jacob, IsaacNewton, IsaacAsimov, isaac"
patron ="(?<=isaac)[a-z]+"
cpatron = re.compile(patron, re.IGNORECASE)
print (cpatron.findall(texte))
donne :
>>>
['Newton', 'Asimov']
>>>
exemple 2
#!/usr/bin/python3
import re
texte = "isaac jacob, IsaacNewton, IsaacAsimov, mimieDany"
patron ="(?<=isaac|m[a-z]{4})[a-z]+"
cpatron = re.compile(patron, re.IGNORECASE)
print (cpatron.findall(texte))
>>>
['Newton', 'Asimov', 'Dany']
>>>
#!/usr/bin/python3
import re
texte = "isaac jacob, Isaac Newton, Isaac La, Isaac Asimov"
motif ="\w{6}(?<=\w{5}\s\w{6})"
cmotif = re.compile(motif, re.IGNORECASE)
print (cmotif.findall(texte))
>>>
['Newton', 'Asimov']
>>>
Le mcanisme est le suivant : il y a d'abord recherche d'un mot de 6 lettres ; puis, partir du dernier
lment consomm, valuation de la condition lookbehind qui doit se terminer sur ce dernier lment
consomm. Il n'y a pas chevauchement puisque tout se passe avant le dernier lment consomm,
pas aprs comme dans le lookahead.