La bibliothèque (Python 3)

Elle se compose de modules, que l'on doit importer (mot clé import).

À explorer : https://docs.python.org/3/py-modindex.html

  • sys : sys.argv, sys.stdin... principalement
  • os : fonctions "bas niveau" (appels système)
  • re : expressions régulières
  • math : flottants, complexes
  • pickle, cPickle : (dé)sérialisation
  • shelve : dictionnaires persistants
  • urllib, urllib2 : http
  • html.parser : comme son nom l'indique ...
  • xmlrpclib : "Remote Procedure Call" (web services)
  • cgi : Common Gateway Interface
  • sqlite3 : Bases de données SQLite
  • socket : réseau bas niveau

Il y a de nombreux paquetages http://pypi.python.org/pypi (environ 120000) pour à peu près n'importe quoi ...

Entrées/sorties : le module sys

Exporte en particulier sys.stdin, sys.stdout, sys.stderr, sys.argv, sys.exit.

In [1]:
import sys
sys.stdout.write('Hello!\n') # équivalent de 'print (Hello!)'
Hello!
In [2]:
sys.stderr.write('Raté !')
Raté !
In [3]:
sys.getfilesystemencoding()
Out[3]:
'utf-8'
In [4]:
sys.getrecursionlimit()
Out[4]:
2000
In [5]:
sys.platform
Out[5]:
'linux'

Appels système : os et os.path

Permet d'utiliser le système de manière indépendante de la plateforme.

In [6]:
import os
os.listdir('toto') # appelle 'ls' sous linux, et 'dir' sous windows
Out[6]:
['link', '2', '3', 'ga', 'meu', '1', 'bu', 'zo']
In [7]:
!ls -l toto
total 16
-rw-rw-r-- 1 jyt jyt    0 oct.  12  2021 1
-rw-rw-r-- 1 jyt jyt    0 oct.  12  2021 2
-rw-rw-r-- 1 jyt jyt    0 oct.  12  2021 3
drwxrwxr-x 2 jyt jyt 4096 oct.  12  2021 bu
drwxrwxr-x 2 jyt jyt 4096 oct.  12  2021 ga
lrwxrwxrwx 1 jyt jyt    4 oct.  12  2021 link -> bu/5
drwxrwxr-x 2 jyt jyt 4096 oct.  12  2021 meu
drwxrwxr-x 2 jyt jyt 4096 oct.  12  2021 zo
In [8]:
os.environ['HOME'] # variables d'environnement (dictionnaire)
Out[8]:
'/home/jyt'
In [9]:
print (os.environ.keys())
KeysView(environ({'CLUTTER_IM_MODULE': 'xim', 'LS_COLORS': 'rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=00:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.zst=01;31:*.tzst=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.wim=01;31:*.swm=01;31:*.dwm=01;31:*.esd=01;31:*.jpg=01;35:*.jpeg=01;35:*.mjpg=01;35:*.mjpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.m4a=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.oga=00;36:*.opus=00;36:*.spx=00;36:*.xspf=00;36:', 'LESSCLOSE': '/usr/bin/lesspipe %s %s', 'LANG': 'fr_FR.UTF-8', 'GDM_LANG': 'fr_FR', 'DISPLAY': ':0', 'GTK_OVERLAY_SCROLLING': '1', 'COLORTERM': 'truecolor', 'XDG_VTNR': '7', 'SSH_AUTH_SOCK': '/run/user/1000/keyring/ssh', 'MANDATORY_PATH': '/usr/share/gconf/cinnamon.mandatory.path', 'XDG_SESSION_ID': 'c2', 'XDG_GREETER_DATA_DIR': '/var/lib/lightdm-data/jyt', 'USER': 'jyt', 'DESKTOP_SESSION': 'cinnamon', 'QT4_IM_MODULE': 'xim', 'GNOME_TERMINAL_SCREEN': '/org/gnome/Terminal/screen/ed476182_26af_4f86_868c_051a4ba5039a', 'DEFAULTS_PATH': '/usr/share/gconf/cinnamon.default.path', 'PWD': '/home/jyt/ens/M1_python', 'HOME': '/home/jyt', 'SSH_AGENT_PID': '1197', 'QT_ACCESSIBILITY': '1', 'XDG_SESSION_TYPE': 'x11', 'XDG_DATA_DIRS': '/home/jyt/.local/share/flatpak/exports/share:/var/lib/flatpak/exports/share/:/usr/share/cinnamon:/usr/share/gnome:/home/jyt/.local/share/flatpak/exports/share:/var/lib/flatpak/exports/share:/usr/local/share:/usr/share', 'XDG_SESSION_DESKTOP': 'cinnamon', 'GJS_DEBUG_OUTPUT': 'stderr', 'GTK_MODULES': 'gail:atk-bridge', 'TERM': 'xterm-color', 'SHELL': '/bin/bash', 'VTE_VERSION': '5202', 'XDG_SEAT_PATH': '/org/freedesktop/DisplayManager/Seat0', 'XMODIFIERS': '@im=none', 'XDG_CURRENT_DESKTOP': 'X-Cinnamon', 'GPG_AGENT_INFO': '/run/user/1000/gnupg/S.gpg-agent:0:1', 'GNOME_TERMINAL_SERVICE': ':1.67', 'XDG_SEAT': 'seat0', 'SHLVL': '1', 'LANGUAGE': 'fr_FR', 'GDMSESSION': 'cinnamon', 'GNOME_DESKTOP_SESSION_ID': 'this-is-deprecated', 'LOGNAME': 'jyt', 'DBUS_SESSION_BUS_ADDRESS': 'unix:abstract=/tmp/dbus-EmjFsjx8bu,guid=4488bce740c823b90eae1cd1633d4566', 'XDG_RUNTIME_DIR': '/run/user/1000', 'XAUTHORITY': '/home/jyt/.Xauthority', 'XDG_SESSION_PATH': '/org/freedesktop/DisplayManager/Session0', 'XDG_CONFIG_DIRS': '/etc/xdg/xdg-cinnamon:/etc/xdg', 'PATH': '/home/jyt/anaconda3/bin:/home/jyt/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin', 'CINNAMON_VERSION': '3.8.9', 'GJS_DEBUG_TOPICS': 'JS ERROR;JS LOG', 'SESSION_MANAGER': 'local/balazuc:@/tmp/.ICE-unix/1117,unix/balazuc:/tmp/.ICE-unix/1117', 'LESSOPEN': '| /usr/bin/lesspipe %s', 'GTK_IM_MODULE': 'xim', 'OLDPWD': '/home/jyt', '_': '/home/jyt/anaconda3/bin/jupyter', 'JPY_PARENT_PID': '2476', 'CLICOLOR': '1', 'PAGER': 'cat', 'GIT_PAGER': 'cat', 'MPLBACKEND': 'module://ipykernel.pylab.backend_inline'}))

Une des fonctions les plus utiles est os.walk (parcours récursif d'une arborescence):

In [10]:
tree = os.walk('toto')
print (tree)
<generator object walk at 0x7fa70bf6d888>
In [11]:
list(tree)
Out[11]:
[('toto', ['ga', 'meu', 'bu', 'zo'], ['link', '2', '3', '1']),
 ('toto/ga', [], ['4']),
 ('toto/meu', [], ['8']),
 ('toto/bu', [], ['6', '5']),
 ('toto/zo', [], ['7'])]
In [12]:
ls -R toto
toto:
1  2  3  bu/  ga/  link@  meu/  zo/

toto/bu:
5  6

toto/ga:
4

toto/meu:
8

toto/zo:
7

On voit que os.walk retourne une liste de triplets de la forme

(repertoire, [liste de repertoires], [liste de fichiers])

Pour savoir si un chemin représente un répertoire, un fichier ou un lien symbolique, on utilise os.path:

In [13]:
os.path.islink('/home/jyt/ens/M1_python/toto')
Out[13]:
False
In [14]:
os.path.islink('/home/jyt/ens/M1_python/toto/link')
Out[14]:
True
In [15]:
os.stat('/home/jyt/ens/M1_python/toto')
Out[15]:
os.stat_result(st_mode=16893, st_ino=8667102, st_dev=2054, st_nlink=6, st_uid=1000, st_gid=1000, st_size=4096, st_atime=1664953908, st_mtime=1634051854, st_ctime=1634051854)
In [16]:
oct(_.st_mode) # les 3 derniers chiffres en octal correpondent aux permissions
Out[16]:
'0o40775'
In [18]:
os.rename('toto','baz')
In [19]:
!ls baz
1  2  3  bu  ga  link  meu  zo
In [20]:
os.system('echo "blablabla">baz/blu') # execute une commande ou un programme
Out[20]:
0
In [21]:
cat baz/blu
blablabla

Pickle : mise en bocal

Pour sauvegarder des données au format Python.

Surtout utile pour sauvegarder des sessions.

On ne peut pas tout sauver (sockets, modules...).

In [22]:
import pickle
f = open('/tmp/toto','wb') # sauvegarde 
pickle.dump(47,f)
pickle.dump(sys.argv,f)
pickle.dump({'canard':'coin', 'chat':'miaou'},f)
f.close()
In [23]:
f = open('/tmp/toto','rb')     # rechargement 
try:
    while 1: print (pickle.load(f))
except EOFError: pass
47
['/home/jyt/anaconda3/lib/python3.6/site-packages/ipykernel_launcher.py', '-f', '/run/user/1000/jupyter/kernel-14711f89-3ba2-49f4-b22e-cfc7ae67acad.json']
{'canard': 'coin', 'chat': 'miaou'}

Shelve

Table de hachage stockée sur disque.

Restrictions : les mêmes que pour pickle. De plus, les clés doivent être des chaînes.

In [24]:
import shelve
d = shelve.open('titi')
d['ga'] = (1,2)
d['bu']= 'abracadabra'
d['zo'] = 3.1415926535
d['meu'] = {'a':'b'}
d.close()
In [25]:
d = shelve.open('titi')
print (d.keys())
print(list(d.keys()))
['ga', 'bu', 'zo', 'meu']
d['bu'] = list(range(3))
d['bu'].append(8)
print (d['bu']) # Un piège : l'attribut "writeback" est False par defaut
KeysView(<shelve.DbfilenameShelf object at 0x7fa70ae51b00>)
['ga', 'bu', 'zo', 'meu']
[0, 1, 2]

Expressions régulières

Module re

re.match(regex, chaîne) et re.search(regex, chaîne) retournent (en cas de match) un objet de type Match.

re.match ne cherche qu'au début de la chaîne.

re.search cherche à n'importe quelle position.

re.findall retourne une liste de toutes les occurences trouvées.

Recherches multiples : re.compile construit un automate.

Pratique : les raw strings

In [26]:
"abc\n\1def" 
Out[26]:
'abc\n\x01def'
In [27]:
print(_)
abc
def
In [28]:
r"abc\n\1def"
Out[28]:
'abc\\n\\1def'
In [29]:
print ("abc\n\1def")
abc
def
In [30]:
print (r"abc\n\1def")
abc\n\1def

Dans une chaîne ordinaire, \n est interprété comme un retour ligne. Pour avoir le caractère '\' suivi du caracère 'n', il faut faire précéder le '\' d'un autre '\', qui est le caractère d'échappement.

Les rawstrings interprètent '\' comme un caractère ordinaire.

In [31]:
import re
m = re.search(r't(.)t\1', 'le tutu') # le \ a une signification spéciale dans les regexp
In [32]:
m
Out[32]:
<_sre.SRE_Match object; span=(3, 7), match='tutu'>

On verra plus loin la signification de cet exemple.

Le parseur python interprète le caractère '\' dans une chaîne comme un caractère d'échappement indiquant le début du nom d'un caractère spécial, comme \n,\t,\x2a,\54,....

Le module re utilise aussi '\' comme caractère d'échappement pour modifier la signification des caractères spéciaux comme *, ., $, ^.

La calamité est qu'on doit parfois échapper le caractère d'échappement (quand le caractère spécial est reconnu par les deux parseurs) et parfois non (quand le caractère spécial n'est pas reconnu par le parseur python).

Dans une raw string, le parseur python ne substituera pas les caractères spéciaux à leur encodage.

Un test commode

Les expressions régulières sont puissantes, mais d'un maniement délicat. Le petit test suivant (emprunté au livre de Pilgrim) permet de visualiser leur effet :

In [34]:
def re_show(pat, s):
    print (re.compile(pat, re.M).sub("{\g<0>}", s.rstrip()),'\n')

La compilation avec l'option re.M permet de traiter une chaîne contenant des sauts de lignes.

L'expression $\tt\backslash g<0>$ représente la chaîne matchée, qui sera donc substituée à elle même, entourée d'accolades.

In [35]:
s = "le cheval de mon cousin ne mange du foin que le dimanche"
p = r'(\b\w*in\b)' # un "bord" (\b) suivi de 0 ou plusieurs caractères alphabétiques (\w*), 
#des lettres i et n, et d'un bord
re_show(p,s)
le cheval de mon {cousin} ne mange du {foin} que le dimanche 

In [36]:
t = """ceci \\ est un \\backslash
mais cela \\n n'est pas un \n saut de ligne"""
t
Out[36]:
"ceci \\ est un \\backslash\nmais cela \\n n'est pas un \n saut de ligne"
In [37]:
print (t)
ceci \ est un \backslash
mais cela \n n'est pas un 
 saut de ligne
In [38]:
re_show('\n|\\\\',t)
ceci {\} est un {\}backslash{
}mais cela {\}n n'est pas un {
} saut de ligne 

In [39]:
re_show(r'\n|\\',t) # autre version
ceci {\} est un {\}backslash{
}mais cela {\}n n'est pas un {
} saut de ligne 

Métacaractères

Ce sont les suivants

. ^ $ * + ? { } [ ] \ | ( ) \A \Z \b \B

"[" et "]" spécifient une classe de caractères :

[abcd] ou [a-d].

Les métacaractères ne sont pas actifs dans une classe : [a-c(?\$] contient les caractères a,b,c,(,?,$.

Un ^ au début définit le complémentaire : les caractères non alphanumériques sont

[^a-zA-Z0-9].

Le \ est le caractère d'échappement.

In [40]:
re_show(r'[au\n\\]',t)
ceci {\} est {u}n {\}b{a}cksl{a}sh{
}m{a}is cel{a} {\}n n'est p{a}s {u}n {
} s{a}{u}t de ligne 

Classes prédéfinies

\d  équivalent à [0-9].
\D  équivalent à [^0-9].
\s  équivalent à [ \t\n\r\f\v].
\S  équivalent à [^ \t\n\r\f\v].
\w  équivalent à alphanumérique (ou seulement [a-zA-Z0-9\_] si ascii).
\W  est les complémntaire
Ces séquences peuvent être incluses dans une classe. Par exemple,

[\s\\\\] contient tous les blancs et le backslash

In [41]:
re_show(r'[\s\\]',t)
ceci{ }{\}{ }est{ }un{ }{\}backslash{
}mais{ }cela{ }{\}n{ }n'est{ }pas{ }un{ }{
}{ }saut{ }de{ }ligne 

Le métacaractère "." matche tout sauf le saut de ligne.

Il existe un mode re.DOTALL où il matche tout caractère.

Le "?" matche 0 ou 1 fois.

L'étoile <regexp>* signifie 0 ou plusieurs fois <regexp>.

Le plus <regexp>+ signifie 1 ou plusieurs fois <regexp>.

Les accolades <regexp>{m,n} signifient au moins $m$ fois et au plus $n$ fois (<regexp>{n} pour exactement $n$ fois).

In [42]:
re_show(r'o*', 'boogie-woogie')
{}b{oo}g{}i{}e{}-{}w{oo}g{}i{}e{} 

In [43]:
re_show(r'o+', 'boogie-woogie')
b{oo}gie-w{oo}gie 

In [44]:
re_show(r'o{2,4}', 'oh boogie-woogie wooof woooof wooooof')
oh b{oo}gie-w{oo}gie w{ooo}f w{oooo}f w{oooo}of 

La barre verticale <R1>|<R2> matche <R1> ou <R2>. On peut mettre une expression entre parenthèses pour lui appliquer un opérateur comme $*$ ou $+$

In [45]:
s = 'baaababaaababbaababbbabaabaabbbaaaababa'
re_show(r'(a|ba)+',s)
{baaababaaaba}b{baaba}bb{babaabaa}bb{baaaababa} 

Les parenthèses servent aussi à indiquer des groupes (voir plus loin).

^ et \$ marquent respectivement le début et la fin d'une ligne.

In [46]:
re_show('^m|sh$|^\s',t)
ceci \ est un \backsla{sh}
{m}ais cela \n n'est pas un 
{ }saut de ligne 

Le type RegexObject

Les expressions régulières, jusqu'ici données sous forme de chaînes, peuvent être compilées. Le résultat est une instance de la classe RegexObject.

Le module re exporte des fonctions ayant les mêmes noms que les méthodes des RegexObjects :

In [47]:
s='baaababaaababbaababbbabaabaabbbaaaababa'
r = re.compile('((a|ba)+)')
r.findall(s)
Out[47]:
[('baaababaaaba', 'ba'),
 ('baaba', 'ba'),
 ('babaabaa', 'a'),
 ('baaaababa', 'ba')]

A cause des deux paires de parenthèses, findall voit deux groupes, et retourne une liste de couples.

Pour n'avoir que ce qu'on veut, on peut utiliser un groupe non-capturant

In [48]:
r = re.compile('(?:a|ba)+') # noter le ?: au début de la parenthèse interne
r.findall(s)
Out[48]:
['baaababaaaba', 'baaba', 'babaabaa', 'baaaababa']

Les méthodes r.match (matche au début de la chaîne) et r.search (matche n'importe où dans la chaîne) retournent un MatchObject ou None.

La méthode r.findall trouve toutes les occurences (non recouvrantes) de l'expression et retourne une liste. r.finditer retourne un itérateur.

r.split casse la chaîne selon les occurences de r.

r.sub et r.subn remplacent les occurences de r par une chaîne fixée, ou leur appliquent une fonction.

In [49]:
print (re.split(r'\s|\\',t))
['ceci', '', '', 'est', 'un', '', 'backslash', 'mais', 'cela', '', 'n', "n'est", 'pas', 'un', '', '', 'saut', 'de', 'ligne']
In [50]:
re.sub(r'\s+|\\', ' ',t)
Out[50]:
"ceci   est un  backslash mais cela  n n'est pas un saut de ligne"

Le type MatchObject

Les méthodes les plus importantes d'un MatchObject m sont :

  • m.group() ou m.group(0) retourne la chaîne matchée
  • m.start() retourne la position de départ du match
  • m.end() retourne la position de la fin du match
  • m.span() retourne un couple (start, end)
  • m.groups() : une expression peut comporter des groupes, délimités par des parenthèses ...
In [51]:
s='baaababaaababbaababbbabaabaabbbaaaababa'
p = re.compile('((a|ba)+)')
m = p.match(s)
print (m.group())
print (m.span())
baaababaaaba
(0, 12)
In [52]:
m
Out[52]:
<_sre.SRE_Match object; span=(0, 12), match='baaababaaaba'>
In [53]:
p.sub(lambda x:'.'*len(x.group(0)),s)
Out[53]:
'............b.....bb........bb.........'
In [54]:
p = re.compile('(a(b)c)d(e)') # groupes emboîtés
m = p.match('abcde')
m.groups()
('abc', 'b', 'e')
Out[54]:
('abc', 'b', 'e')
In [55]:
print (m.group(0))
print (m.group(1))
print (m.group(2))
print (m.group(3))
abcde
abc
b
e

Groupes non capturants

Évitent que les parenthèses (obligatoires pour encadrer le +) ne soient interprétées comme un groupe devant capturer la première occurence d'une des lettres i,j,a,b,c :

In [56]:
m = re.match('([ij]|[abc])+','aabbjjiijcxabb')
print (m.groups())
print (m.group(0))
print (m.group(1))
('c',)
aabbjjiijc
c
In [57]:
m = re.match('(?:[ij]|[abc])+','aabbcxabb')

print (m.group(0))
m.groups()
aabbc
Out[57]:
()

Les groupes peuvent être nommés en utilisant la syntaxe $\tt(?P<name>...)$

In [58]:
s="le cheval de mon cousin ne mange du foin que le dimanche"
p = re.compile(r'(\b\w*in\b).*(\bd\w*e\b)')
m = p.search(s)

m.groups()
Out[58]:
('cousin', 'dimanche')
In [59]:
p = re.compile(r'(?P<qui>\b\w*in\b).*(?P<quand>\bd\w*e\b)')
m = p.search(s)
m.group('quand')
Out[59]:
'dimanche'

Application d'une fonction aux groupes

Syntaxe : r.sub(f, s, count=0)

f accepte comme argument un MatchObject et retourne la chaîne à utiliser en remplacement du match.

In [60]:
s='''<html>
      <body>
      <H1>Mon beau cours de python</H1>
      <H2>Blabla</H2> et ri et
ra  patati et patata
</body>
</html>'''

def capitalize(m):
    return '<h1>'+ ' '.join([w.capitalize() for w in m.group(1).split()])+'</h1>'

p=re.compile(r'<h1>(.*?)</h1>', re.I|re.M)

print (re.findall(p,s))
print (p.sub(capitalize,s))
['Mon beau cours de python']
<html>
      <body>
      <h1>Mon Beau Cours De Python</h1>
      <H2>Blabla</H2> et ri et
ra  patati et patata
</body>
</html>

On peut utiliser cette technique pour l'exercice 3 du TD 2 :

In [61]:
import random, re

p = re.compile('(\w)(\w\w+)(\w)', re.M) # reconnaît les mots d'au moins 4 lettres

def touille(m):                         # m est un match object, m.group(2) est le contenu de (\w\w+)
    milieu = list(m.group(2))           # donc le milieu de la chaîne matchée, qu'il faut convertir en
    random.shuffle(milieu)              # liste et nommer pour la mélanger en place
    return m.group(1) + ''.join(milieu) + m.group(3) # on remet la première et la dernière lettre en place


def blurr(s):
    return p.sub(touille,s)
In [62]:
blurr('Il est plus facile de se laver les dents dans un verre à pied que de se laver les pieds dans un verre à dents')
Out[62]:
'Il est plus faicle de se lvear les dtens dnas un verre à pied que de se leavr les pides dnas un verre à dtnes'

Glouton, ou pas ?

Les opérateurs non-gloutons *?, +?, ??, ou {m,n}?, matchent aussi peu de texte que possible

In [63]:
s = '<html><head><title>Title</title>'
print (re.match('<.*>', s).group())
<html><head><title>Title</title>
In [64]:
print (re.match('<.*?>', s).group())
<html>

Options de compilation

  • I ou IGNORECASE : insensible à la casse
  • L ou LOCALE : rend \w, \W, \b, \B dépendants de ce que la locale courante considère comme alphanumérique
  • M ou MULTILINE : ^, $ matchent le début et la fin de chaque ligne, en plus du début et de la fin de la chaîne
  • S ou DOTALL : le point . matche un saut de ligne
  • U ou UNICODE : rend \w, \W, \b, \B dépendants de ce qu'Unicode considère comme alphanumérique
  • X ou VERBOSE : les espaces blancs sont ignorés et # est interprété comme le début d'un commentaire

Mode verbeux

Les options de compilation sont aussi utilisables avec les chaînes (syntaxe (?iLmsux)). En mode verbeux, les espaces sont ignorés et # signale un commentaire :

In [65]:
pat_url = re.compile(  r'''(?x) # flag à mettre au début depuis 3.6
                   ( # verbose identify URLs within text
   (http|ftp|gopher) # make sure we find a resource type
                 :// # needs to be followed by ://
      (\w+[:.]?){2,} # at least two domain groups: (gouv.)(fr)
                (/?| # just the domain name (maybe no /)
          [^ \n\r"]+ # or stuff then space, newline, tab, quote
              [\w/]) # resource name ends in alphanumeric or /
   (?=[\s\.,>)'"\]]) # assert: followed by white or clause ending
                   ) # end of match group''')