caractères et octets -...
TRANSCRIPT
Caractères et octets
bytes
Un nouveau type fondamental, qui ressemble les chaînes str, mais :
● str = séquence de caractères Unicode
● bytes = séquence d'octets
Unicode vs OctetsUne séquence de 6 caractères Unicode:
>>> s = 'aèßβ中文 '
>>> type(s)
<class 'str'>
Une séquence de 3 octets 0xFF, 0x01, 0xAC :
>>> t = b'\xff\x01\xac'
>>> type(t)
<class 'bytes'>
Dans bytes, \xXY où X et Y sont chiffres hexadécimaux, représente l'octet 0xXY.
Unicode● énorme liste de tous les caractères existants au
monde (présent et passé)● définit 1 114 112 code points (sur 32 bits)
Code point Caractère
0x41 = 65 A
0xE8 = 232 è
0xDF = 223 ß
0x4E2D = 20013 中
Séquences d’échappement
Dans bytes :● b'\xX1X2' représente l'octet 0xX1X2.
Dans str :● '\xX1X2'
● '\uX1X2X3X4'
● '\UX1X2X3X4X5X6X7X8'
représentent le caractère Unicode au code point 0xX1X2, 0xX1X2X3X4, 0xX1X2X3X4X5X6X7X8, respectivement.
Encodage de caractères
Les fichier, la mémoire, les connexions réseau etc., sont des séquence d'octets.
Comment convertir du texte en octets ?
Première solution : code ASCII● sur 7 bits (premier bit de l'octet = 0)● 27 = 128 caractères possibles
Les codes entre 0x20 et 0x7E sont les caractères affichable (chiffres, lettres latines, ponctuation, ...)
bytes
Dans les séquences bytes, on peut employer les caractères ASCII.
>>> t = b'a\xffz'
>>> len(t)
3
En fait, si l'un des codes hexadécimaux employés correspond à un caractère ASCII, Python l'affiche automatiquement.
>>> t = b'\x41\x42\xff'
>>> t
b'AB\xff'
Encodage de caractères
On peut aisément encoder du texte anglais avec ASCII, mais que faire pour les autres langues du monde ?
Plusieurs encodages « partiels » ont été proposés au fil des années : ISO-8859-1, ISO-8859-15, Windows-1252, etc. etc. etc.
Solution « universelle » acceptée aujourd'hui :
UTF-8
Recouvre Unicode entièrement.
Encodage de caractères
UTF-8 est un encodage multi-octet à longueur variable.
Chaque caractère Unicode est encodé avec un ou plusieurs octets.
Exemple :
Caractère Unicode Encodage UTF-8
A (0x41) 0x41
è (0xE8) 0xC3 0xA8
ß (0xDF) 0xC3 0x9F
中 (0x4E2D) 0xE4 0xB8 0xAD
Encodage de caractères
Deux méthodes de conversion qui par défaut utilisent l'encodage UTF-8 :
● chaîne (str) →octets (bytes)
>>> 'è'.encode()
b'\xc3\xa8'
● octets (bytes) →chaîne (str)
>>> b'\xc3\xa8'.decode()
'è'
Fichiers et encodage
Avec les fichiers
Ouvrir, lire (ou écrire) des fichiers :
>>> f = open('book.txt', 'r')
>>> s = f.read()
>>> type(s)
<class 'str'>
Avec les fichiers
Les modes 'r', 'w' utilisent implicitement un encodage (normalement UTF-8).
L'encodage utilisé dépend de la plateforme.
Pour le le découvrir :
>>> import locale
>>> locale.getpreferredencoding()
'UTF-8'
Avec les fichiers
On peut aussi ouvrir, lire et écrire les fichiers directement en mode binaire = sans encodage/décodage.
Avec les modes 'rb', 'wb'
>>> f = open('book.txt', 'rb')
>>> s = f.read()
>>> type(s)
<class 'bytes'>
Sérialisation
Sérialisation
Souvent, il y a le besoin de convertir un objet arbitraire en séquence d'octet, pour :● stocker dans un fichier● envoyer sur réseau● communiquer à un autre processus● ...
Cette conversion s'appelle sérialisation.
Sérialisation
En Python, la librairie standard fournit un module très général qui permet la sérialisation et désérialisation d'objets en bytes :
pickle
● objet Python → bytes● bytes → objet Python
L'encodage utilise un format binaire spécifique à Python.
pickle● pickle.dumps(objet)
convertit objet en une séquence d'octets, et retourne le résultat
>>> s = pickle.dumps([3.14, 'hello'])
>>> s
b'\x80\x03]q\x00(G@\t\x1e\xb8Q\xeb\x85\x1fX\x05\x00\x00\x00helloq\x01e.'
● pickle.loads(s)
convertit une séquence d'octets s en objet et retourne le résultat
>>> obj = pickle.loads(b'\x80\x03]q\x00(G@\t\x1e \xb8Q\xeb\x85\x1fX\x05\x00\x00\x00helloq\x01e.')
>>> obj
[3.14, 'hello']
pickle
Deux fonctions qui agissent directement sur les fichier :● pickle.dump(objet, fichier)
convertit objet en une séquence d'octets, et écrit le résultat dans fichier
>>> f = open('basedonne', 'wb')
>>> pickle.dump([3.14, 'hello'], f)● pickle.load(fichier)
lit le contenu de fichier, le convertit en objet, et retourne le résultat
>>> f = open('basedonne', 'rb')
>>> obj = pickle.load(f)
>>> obj
[3.14, 'hello']
pickle
Quels objets sont « pickables » ?
● None, booléens, nombres, chaînes● conteneurs : listes, tuples, dictionnaires (pourvu
que les objets contenus soient « pickables »)● instances des classes
pickle
On peut utiliser pickle pour stocker les instances des classes, mais pour les récupérer il faut avoir déjà la définition de la classe. Normalement cette définition est disponible dans le programme.
Par exemple, on lance le programme suivant :
class Vecteur:
def __init__(self, x, y):
self.x, self.y = x, y
f = open('db.pickle', 'wb')
pickle.dump(Vecteur(3, 4), f)
f.close()
pickle
Si après l'exécution du programme précédent, on essaie dans la console :
>>> f = open('db.pickle', 'rb')
>>> v = pickle.load(f)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: Can't get attribute 'Vecteur' on <module '__main__' (built-in)>
Une exception est levée : la classe Vecteur n'est pas définie.
pickleTrès utile pour créer des simples bases de données, par exemple avec un dictionnaire.
import pickle
def enregistrer_points(p):
f = open('pointsjeu.pickle', 'wb')
pickle.dump(p, f)
f.close()
def lire_points():
f = open('pointsjeu.pickle', 'rb')
p = pickle.load(f)
f.close()
return p
points = {'Jean' : 10, 'Yasmine' : 15, 'Geronimo' : 30}
enregistrer_points(points)
points2 = lire_points()
Expressions régulières
Expressions régulières
Outil puissant pour la recherche du texte basé sur un pattern (motif).
Comme les « wildcards » de la shell :● « *.txt » →book.txt
log.txtblabla.txt.txtetc.
● « ?at.png »→cat.pngbat.pngfat.pngetc.
...mais beaucoup plus puissant.
Expressions régulières
Python utilise des regex similaires à ceux de Perl.
● la plus part de caractères dans une regex correspondent identiquement dans le texte:
toto → toto
Toto → Toto
cat → cat● certains caractères (métacaractères) signalent que
des substitutions sont à faire.Les métacaractères :
. ^ $ * + ? { } [ ] \ | ( )
Expressions régulières
Normalement, la recherche est effectué par ligne.
Dans un texte :
bonjour à tous
hello hello hello world
tous les livres
La regex « tous » trouvera...
Expressions régulières
Normalement, la recherche est effectué par ligne.
Dans un texte :
bonjour à tous
hello hello hello world
tous les livres
La regex « tous » trouvera...
Expressions régulières
Répétitions de l'élément qui précède :● * zéro ou plus répétitions● + au moins une répétition● ? zéro ou une répétition● {n,m} entre n et m répétition
ab*c → ac, abc, abbc, abbbc, ...
ab+c → abc, abbc, abbbc, ...
ab?c → ac, abc
ab{3,5}c → abbbc, abbbbc, abbbbbc
Expressions régulières
Classes de caractèrese avec [ ]
[abc]bla → abla, bbla, cbla
On peut peut utiliser des intervalles Unicode avec le « tiret » :
[a-z]bla → abla, bbla, ... zbla
[0-9] →0, 1, 2, ... 9
x[B-F] → xB, xC, xD, xE, xF
[丠 -严 ] → 丠 , 両 , 丢 , 丣 , 两 , 严
Expressions régulières
Un point « . » correspond à n'importe quel caractère sauf retourne à la ligne
a.b → axb, aùb, a7b, a b, ...
a.*b → a12 21b, axyxyxb, ab, ...
a.?b → ab, axb, aùb, ...
Expressions régulières● ^ début de la ligne● $ fin de la ligne
Dans un texte :
bonjour à tous
hello hello hello world
tous les livres
La regex « ^tous » trouvera...
Expressions régulières● ^ début de la ligne● $ fin de la ligne
Dans un texte :
bonjour à tous
hello hello hello world
tous les livres
La regex « ^tous » trouvera...
Expressions régulières● ^ début de la ligne● $ fin de la ligne
Dans un texte :
bonjour à tous
hello hello hello world
tous les livres
La regex « tous$ » trouvera...
Expressions régulières● ^ début de la ligne● $ fin de la ligne
Dans un texte :
bonjour à tous
hello hello hello world
tous les livres
La regex « tous$ » trouvera...
Expressions régulières
Un barre vertical « | » : opérateur ou.
Dans un text :
Le chien blanc poursuit le chat noir.
La regex « chien|chat » trouvera...
Expressions régulières
Un barre vertical « | » : opérateur ou.
Dans un text :
Le chien blanc poursuit le chat noir.
La regex « chien|chat » trouvera...
Expressions régulières
Parenthèses ( ) pour créer des groupes.
(ab)+ → ab, abab, ababab, ...
(cat|dog)+ →
cat, dog, catcat, catdog, dogcat, ...
Expressions régulières
L'antislash introduit ensembles de caractères prédéfinis :
\d chiffre
\D non-chiffre
\w alphanumérique
\W non-alphanumérique
\s blanc
\S non-blanc
\w+\s\w+ → foo bar, a b, c123 1919
Expressions régulières
L'antislash permet aussi d'introduire les métacaractères littéralement :
\*\(hello\)\* → *(hello)*
Bonjour \? → Bonjour ?
3\.14 → 3.14
Expressions régulières
En Python : module standard re.
La regex est compilée à partir d'une chaîne :
import re
p = re.compile('a.?b')
Avec l'objet qui représente la regex compilée, on peut effectuer des recherches.
Expressions régulières
Problème : l'antislash est déjà utilisé dans les chaînes Python pour les caractères spéciaux.
Pour éviter une collision, on veut empêcher à Python d'interpréter l'antislash, et le passer littéralement aux fonctions RE.
Ça se fait en préfixant la chaîne avec r :
p = re.compile(r'bonjour \?')
q = re.compile(r'\\o/')
r = re.compile(r'\w+\d\w+')
Expressions régulièresLes méthodes principales d'un objet regex :
● p.match(s)
Teste si la regex correspond au début de la chaîne s● p.search(s)
Teste si la regex correspond quelque part dans s● p.finditer(s)
Trouve toute le correspondances de la regex et renvoie un itérateur
● p.findall(s)
Trouve toute le correspondances de la regex et renvoie une liste
Expressions régulières.match(), .search() retournent un objet « match », .finditer() retourne un itérateur sur des objets « match »
>>> p = re.compile('a.?b')
>>> m = p.search('balba')
>>> m
<_sre.SRE_Match object; span=(1, 4), match='alb'>
On peut récupérer les infos d'un objet « match » avec :
>>> m.group()
'alb'
>>> m.span()
(1, 4)
Expressions régulières.findall() retourne une liste de chaînes avec toutes les occurences.
>>> p = re.compile(r'\d+')
>>> p.findall('31 octobre, 12 janvier, 4 kilos')
['31', '12', '4']
Expressions régulières
Il y a des fonctions .match(), .search(), .finditer(), .findall() au niveau du module, pour éviter de compiler la regex :
>>> m = re.search('a.?b', 'balba')
Équivalent à
>>> p = re.compile('a.?b')
>>> m = p.search('balba')
Expressions régulièresParfois, on veut récupérer seulement une partie du pattern.
Ex. dans un texte :
a54b x12x z64x x337x c567c v6w x1x
on veut trouver tous les nombres entre deux x :
x\d+x
Pour sauvegarder une partie du pattern, on peut employer le groupage :
x(\d+)x
Chaque « groupe » est stocké séparément. Les groupes sont récupérable avec la méthode .groups() de l'objet match.
for m in re.finditer(r'x(\d+)x', s):
nombre = m.groups()[0]
print(nombre)