Caractères et octets -...

Post on 29-Oct-2018

230 views 0 download

Transcript of Caractères et octets -...

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)