01° Voici un script permettant de créer un fichier texte. Suivre les instructions et questions décrites ci-dessous.
Créer un répertoire qu'on nommera activiteFichier.
Enregistrer ce script de le répertoire activiteFichier.
📁 activiteFichier
📄 script_test.py
1
2
3
4
5
6
7
8
9
# 1 - Création de l'objet-fichier : ouverture en mode w (write)obj_fichier=open('aaa.txt','w',encoding="utf-8")# 2 - Remplissage progressif du fichierobj_fichier.write("Premier contenu")obj_fichier.write("Deuxième ajout")# 3 - Fermeture de l'objet-fichierobj_fichier.close()
Utiliser le script. Regarder le contenu de votre répertoire : vous devriez constater la présence d'un nouveau fichier nommée 'aaa.txt' dans votre répertoire.
📁 activiteFichier
📄 script_test.py
📄 aaa.txt
Pourquoi le fichier est-il créé dans le même répertoire que le fichier Python ?
...CORRECTION...
Tout simplement car on ne donne que le nom du fichier à créer.
Il s'agit donc d'une adresse relative, relative à l'endroit où se trouve le fichier Python.
Relative à l'endroit où se situe le fichier contenant l'appel à open(). Le fichier texte est donc créé dans le même répertoire que celui du programme.
02° Ouvrir le fichier-texte pour voir son contenu. Que voyez-vous de surprenant ?
...CORRECTION...
Voici le contenu :
Première ligneDeuxième ligne
On constate donc qu'il n'y a pas de passage à la ligne. Alors qu'on aurait pu le croire. La méthode write() porte donc bien son nom : elle écrit des octets dans le fichier. Si on ne signale pas qu'il faut insérer l'octet signalant le passage à la ligne, la méthode ne le rajoute pas automatiquement. Elle fait simplement ce qu'on lui demande.
La méthode write() ne fait que rajouter le contenu, sans chercher à rajouter de passage à la ligne.
Si vous voulez rajouter les passages à la ligne, il faudra le dire, en rajoutant des passages à la ligne \n dans votre string une fois que vous avez fini une ligne.
03° Tester le script suivant dans lequel nous tentons cette fois de rajouter des passages à la ligne. Ouvrir le fichier-texte après avoir exécuté le script.
1
2
3
4
5
6
7
8
9
# 1 - Création de l'objet-fichier : ouverture en mode w (write)obj_fichier=open('aaa.txt','w',encoding="utf-8")# 2 - Remplissage progressif du fichierobj_fichier.write("Voici une nouvelle ligne\n")obj_fichier.write("Cette fois, c'est la dernière ligne du fichier.\n")# 3 - Fermeture de l'objet-fichierobj_fichier.close()
Question
Qu'est devenu l'ancien contenu ?
...CORRECTION...
Voici le contenu :
Voici une nouvelle ligne↲
Cette fois, c'est la dernière ligne du fichier.↲
Chose surprenante : le nouveau contenu a supprimé le premier contenu !
Alors comment faire pour rajouter du contenu sans supprimer l'ancien ?
1.1 Créer un fichier-texte avec la fonction open()
Création avec open()
Pour écrire dans un fichier-texte, il faut commencer par l'ouvrir avec la fonction open() : cette fonction permet de créer un objet-fichier dont on va pouvoir utiliser la référence pour interagir avec le vrai contenu en mémoire.
Open avec l'option "w", le mode write (écrasement)
1
obj_fichier=open('aaa.txt','w',encoding="utf-8")
Cela crée l'objet-fichier obj_fichier mais en supprimant tout le contenu éventuel précédent.
On utilise ce mode lorsqu'on veut créer un nouveau contenu.
Open avec l'option "a", le mode append (rajout)
1
obj_fichier=open('aaa.txt','a',encoding="utf-8")
Cela crée l'objet-fichier obj_fichier mais en récupérant l'ancien contenu s'il existe.
Comme pour les tableaux dynamiques (type list en Python), "append" veut dire qu'on rajoute le contenu à la fin du contenu précédent.
On utilise ce mode lorsqu'on veut rajouter du contenu sans perdre l'ancienne information.
1.2 Rajout de contenu avec la méthode write()
On utilise la notation avec le point qu'on utilise sur les objets : fichier-objet.méthode().
Ceci ajoute le texte "Bonjour" dans l'objetfichier MAIS sans passer à la ligne, ni avant, ni après.
2
obj_fichier.write("Bonjour")
Si vous voulez ajouter un passage à la ligne, il faudra l'indiquer à l'aide de la présence du caractère \n dans la chaîne.
2
obj_fichier.write("Voici une nouvelle ligne\n")
1.3 Fermeture de l'objet-fichier avec la méthode close()
3
obj_fichier.close()
Attention : si la fermeture est mal effectuée, ou pas effectuée, cela peut entrainer des problèmes lors d'une prochaine ouverture. Pensez donc bien à fermer votre objet.
04° Créer un script qui permet cette fois de rajouter deux lignes au fichier 'aaa.txt' sans pour autant supprimer le texte déjà enregistré.
...CORRECTION...
Le fichier est déjà créé. Il suffit donc d'utiliser l'argument 'a' et pas l'argument 'w.
1
2
3
4
5
6
7
8
9
# 1 - Création de l'objet-fichier : ouverture en mode a (append)obj_fichier=open('aaa.txt','a',encoding="utf-8")# 2 - Remplissage progressif du fichierobj_fichier.write("Et cette fois, on supprime ou pas ?\n")obj_fichier.write("Ah ben non. On rajoute.\n")# 3 - Fermeture de l'objet-fichierobj_fichier.close()
Voici le contenu obtenu après exécution :
Voici une nouvelle ligne↲
Cette fois, c'est la dernière ligne du fichier.↲
Et cette fois, on supprime ou pas ?↲
Ah ben non. On rajoute.↲
Nous savons donc maintenant créer un fichier-texte ou rajouter des caractères à la suite des précédents.
1.4 Exemple d'écriture dans un fichier
Exemple où on remplace intégralement le contenu d'un fichier.
1
2
3
4
5
6
7
8
9
# 1 - Création de l'objet-fichier : ouverture en mode w (write)obj_fichier=open('aaa.txt','w',encoding="utf-8")# 2 - Remplissage progressif du fichierobj_fichier.write("Premier contenu")obj_fichier.write("Deuxième ajout")# 3 - Fermeture de l'objet-fichierobj_fichier.close()
Exemple où on rajoute à la fin du fichier, sans écraser l'ancien contenu.
1
2
3
4
5
6
7
8
9
# 1 - Création de l'objet-fichier : ouverture en mode w (write)obj_fichier=open('aaa.txt','a',encoding="utf-8")# 2 - Remplissage progressif du fichierobj_fichier.write("Voici une nouvelle ligne\n")obj_fichier.write("Cette fois, c'est la dernière ligne du fichier.\n")# 3 - Fermeture de l'objet-fichierobj_fichier.close()
Saut à la ligne avec Windows
La lecture d'un fichier-texte issu de Windows montre parfois la présence d'un caractère particulier en plus de \n : le caractère d'échappement retour-chariot \r (octet contenant 13 en ASCII).
Voyons comment lire les caractères de notre fichier.
Cette fois, nous allons l'ouvrir avec l'argument 'r' pour READ. La liaison sera ainsi effectuée uniquement en lecture.
Nous allons voir :
Comment lire une ligne à la fois avec readline()
Comment lire toutes les lignes readline() dans une boucle TANT QUE
Comment lire toutes les lignes readline() dans une boucle POUR
Comment lire un caractère à la fois avec read()
Comment gérer l'encodage utilisé sur le fichier-texte
2.1 Lecture manuelle d'une ligne avec la méthode readline()
Lorsqu'on ouvre un fichier-objet, Python génère une tête de lecture qui pointe initialement au début du fichier-texte.
La méthode readline() renvoie un string contenant la prochaine ligne qu'on peut lire à partir de la position actuelle de la tête de lecture du fichier-objet. Elle renvoie dans le string situé entre
La tête de lecture
Le prochain \n (Line Feed, 10 en ASCII) ou la fin du fichier (EOF, End Of File)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 1 - Création de l'objet-fichier : ouverture en mode r (read)obj_fichier=open('aaa.txt','r',encoding="utf-8")# 2 - Lecture progressive du fichiera=obj_fichier.readline()print(a,end="")b=obj_fichier.readline()print(b,end="")c=obj_fichier.readline()print(c,end="")d=obj_fichier.readline()print(d,end="")# 3 - Fermeture de l'objet-fichierobj_fichier.close()
Voici un exemple de résultat :
Voici une nouvelle ligne
Cette fois, c'est la dernière ligne du fichier.
Et cette fois, on supprime ou pas ?
Ah ben non. On rajoute.
Ici, chaque ligne sera simplement affichée sur la console à l'aide de la fonction native print(). Pourquoi avoir rajouté end="" ?
Tout simplement car le \n fait partie du string renvoyé. Si vous ne modifiez pas la fin du print(), vous aurez deux passages à la ligne : celui à l'intérieur du string et celui généré par défaut par print().
>>> a
'Voici une nouvelle ligne\n'>>> b
'Cette fois, c'est la dernière ligne du fichier.\n'>>> c
'Et cette fois, on supprime ou pas ?\n'>>> c
'Ah ben non. On rajoute.\n'
05° Utiliser le script suivant puis rajouter quelques autres lectures de façon à tenter de lire plus de lignes que le fichier n'en possède.
Questions
Quel est le string qu'on récupère lorsqu'on lit alors qu'on se trouve à la fin du fichier ?
Python déclenche-t-il une erreur lorsqu'on va 'trop loin' ?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 1 - Création de l'objet-fichier : ouverture en mode r (read)obj_fichier=open('aaa.txt','r',encoding="utf-8")# 2 - Lecture progressive du fichiera=obj_fichier.readline()print(a,end="")b=obj_fichier.readline()print(b,end="")c=obj_fichier.readline()print(c,end="")d=obj_fichier.readline()print(d,end="")# 3 - Fermeture de l'objet-fichierobj_fichier.close()
...CORRECTION...
La fin de fichier est représenté par un string vide "".
Une fois en fin de fichier, on peut tenter de lire autant de lignes qu'on veut, on n'obtient pas une erreur mais on lit simplement encore et encore un string vide "".
Avec cette façon de faire, si on a 1500 lignes, on est parti pour taper 1500 fois readline()...
Heureusement, notre objet-fichier obj_fichier est un itérable : on peut utiliser une boucle FOR pour lire ses éléments un par un.
Je présente ci-dessous deux manières de lire toutes les lignes d'un fichier-texte en utilisant une boucle.
2.2 Boucle while avec la méthode readline()
Principe
On lit et enregistre une première ligne
TANT QUE la ligne n'est pas vide
On fait le traitement de cette ligne
On lit et enregistre la ligne suivante
Fin du TANT QUE
Il faudra donc veiller à initialiser la variable de boucle avec quelque chose qui permette de rentrer une première fois dans la boucle.
Exemple
1
2
3
4
5
6
7
8
9
10
11
12
# 1 - Création de l'objet-fichier : ouverture en mode r (read)obj_fichier=open('aaa.txt','r',encoding="utf-8")# 2 - Lecture ligne par ligneligne=obj_fichier.readline()whileligne!="":print(ligne,end="")# Traitement de la ligne actuelleligne=obj_fichier.readline()# Lecture et stockage de la ligne suivante# 3 - Fermeture de l'objet-fichierobj_fichier.close()
06° Utiliser ce script de lecture : il va vous permettre de lire et afficher en boucle les "lignes" du fichier.
1
2
3
4
5
6
7
8
9
10
11
12
# 1 - Création de l'objet-fichier : ouverture en mode r (read)obj_fichier=open('aaa.txt','r',encoding="utf-8")# 2 - Lecture ligne par ligneligne=obj_fichier.readline()whileligne!="":print(ligne,end="")ligne=obj_fichier.readline()# 3 - Fermeture de l'objet-fichierobj_fichier.close()
Questions
Quelles sont les 3 lignes qui appartiennent au TANT QUE ?
L7 : Tant qu'on n'a pas atteint la fin du fichier.
L8 : Afficher cette ligne (sans rajouter de passage à la ligne, il est intégré dans le string de la ligne)
L9 : lire et stocker la ligne suivante.
La ligne 5 permet simplement de créer une première ligne à lire. Si elle n'est pas vide, on réalisera donc la boucle. Si elle est vide dès le départ, on ne réalisera même pas un tour de boucle.
07° Tester cette nouvelle version. La seule différence se trouve en ligne 7.
Question
Que signifie la nouvelle condition ?
1
2
3
4
5
6
7
8
9
10
11
12
# 1 - Création de l'objet-fichier : ouverture en mode r (read)obj_fichier=open('aaa.txt','r',encoding="utf-8")# 2 - Lecture ligne par ligneligne=obj_fichier.readline()whileligne:print(ligne,end="")# Traitement de la ligne actuelleligne=obj_fichier.readline()# Lecture et stockage de la ligne suivante# 3 - Fermeture de l'objet-fichierobj_fichier.close()
...CORRECTION...
L'interpréteur Python interprète l'expression derrière le while comme un booléen, même si cette expression ne l'est pas.
Il suffit de se souvenir qu'en Python :
False, c'est tout ce qui est nul ou vide.
True, c'est... tout le reste.
La condition de poursuite veut donc dire de continuer si ligne contient autre chose que 0, False, None, une chaîne vide ou un tableau non vide, ou un dictionnaire non vide ou un tuple non vide...
Puisque ligne est un string, cela veut donc dire de continuer TANT QUE la ligne contient quelque chose.
2.3 Boucle while avec la méthode readline() V2
Evaluer un non-booléen en booléen en Python
!!! A SAVOIR PAR COEUR !!!
En Python, un contenu VIDE ou NUL est évalué à False si on demande un résulat booléen.
Dans tous les autres cas, le résultat est True.
Conséquence sur la condition de poursuite
On obtient donc un code encore plus simple que le précédent :
1
2
3
4
5
6
7
8
9
10
11
12
# 1 - Création de l'objet-fichier : ouverture en mode r (read)obj_fichier=open('aaa.txt','r',encoding="utf-8")# 2 - Lecture ligne par ligneligne=obj_fichier.readline()whileligne:print(ligne,end="")# Traitement de la ligne actuelleligne=obj_fichier.readline()# Lecture et stockage de la ligne suivante# 3 - Fermeture de l'objet-fichierobj_fichier.close()
L'objet-fichier est un itérable en Python : nous allons donc pouvoir utiliser un POUR.
2.4 Boucle for avec la méthode readline()
Principe
On lit l'une des lignes à chaque tour de boucle
Et c'est tout.
C'est comme lire une à une les valeurs d'un tableau.
Ici, on lit une à une les lignes du fichier.
Exemple
1
2
3
4
5
6
7
8
9
# 1 - Création de l'objet-fichier : ouverture en mode wobj_fichier=open('aaa.txt','r',encoding="utf-8")# 2 - Remplissage progressif du fichierforligneinobj_fichier:print(ligne,end="")# 3 - Fermeture de l'objet-fichierobj_fichier.close()
Le plus explicite est donc de nommer la variable de boucle ligne plutôt que k, x ou autre, puisqu'elle va contenir l'une des lignes, une par tour de boucle.
08° Utiliser ce script de lecture : il va vous permettre de lire et afficher en boucle les "lignes" du fichier.
En ligne 2, on notera qu'on demande le type de l'objet-fichier obj_fichier.
Question : quel est son type ? est-ce un simple texte ?
1
2
3
4
5
6
7
8
9
10
# 1 - Création de l'objet-fichier : ouverture en mode wobj_fichier=open('aaa.txt','r',encoding="utf-8")print(type(obj_fichier))# 2 - Remplissage progressif du fichierforligneinobj_fichier:print(ligne,end="")# 3 - Fermeture de l'objet-fichierobj_fichier.close()
...CORRECTION...
Cet objet est de type TextIOWrapper. Il s'agit d'un objet gestionnaire de flux entrant (input)-sortant(output). Il ne s'agit donc pas directement du texte ou du fichier mais d'un objet informatique permettant d'interagir avec le fichier dont les octets sont enregistrés en mémoire.
obj_fichier est un objet capable de faire interface entre notre programme et le fichier réel (la suite d'octets).
On peut également lire les caractères un par un avec la méthode read() qui permet de lire le flux de données en fonction d'un nombre de caractères plutôt que d'aller nécessairement jusqu'au prochain passage à la ligne /n.
2.5 Lire un caractère à la fois avec la méthode read()
Principe
La méthode read() lit le flux de données en fonction d'un nombre de caractères plutôt que d'aller nécessairement jusqu'au prochain passage à la ligne /n.
On lui fournit en argument le nombre de caractères à lire. Si on ne précise pas d'argument, la méthode va renvoyer... la totalité du flux.
Exemple
Voici un script de lecture qui vous permettra de lire les caractères enregistrés dans le fichier un par un. On affiche chaque caractère, à part les a ou les A qu'on décide de remplacer par @ .
On utilise un print() dont le caractère final est une étoile, de façon à bien voir les successions de lecture.
10
print(lecture,end="*")
Voici le script :
1
2
3
4
5
6
7
8
9
10
11
12
13
# 1 - Création de l'objet-fichier : ouverture en mode wobj_fichier=open('aaa.txt','r',encoding="utf-8")# 2 - Remplissage progressif du fichierlecture="o"# Affectation quelconque pour rentrer une première fois dans la bouclewhilelecture:lecture=obj_fichier.read(1)iflecture=='a'orlecture=='A':lecture='@'print(lecture,end="*")# 3 - Fermeture de l'objet-fichierobj_fichier.close()
09° Utiliser le script présenté ci-dessus et visualiser le résultat.
Questions
A quoi voit-on que l'espace est bien un caractère comme un autre ?
A quoi voit-on que le LINE FEED est bien un caractère comme un autre ?
Modifier alors le programme pour qu'il fournisse des blocs de 5 caractères à la fois.
On voit bien que l'espace est un caractère puisqu'il y a apparition d'une étoile derrière chaque caractère dans le code et que derrière les espaces on trouve bien ... une étoile.
Idem pour les passages à la ligne (LINE FEED) : le caractère provoque le passage à la ligne car c'est un caractère de contrôle et pas juste un caractère d'imprimerie. Ici, on constate donc qu'il y a une étoile en début de chaque nouvelle ligne. Le LINEFEED est donc bien un caractère.
Si on lance le code en lisant 5 caractères à la fois en ligne 7, on obtient ceci :
Voici* une *nouve*lle l*igne
*Cette* fois*, c'e*st la* dern*ière *ligne* du f*ichie*r.
Et* cett*e foi*s, on* supp*rime *ou pa*s ?
A*h ben* non.* On r*ajout*e.
**
Une dernière chose avec la lecture : pour lire un fichier-texte, il faut en réalité se rendre compte qu'on lit des octets et qu'on les décode en respectant un certain encodage.
Ici, nous avons créé le fichier en utilisant l'encodage UTF-8 (de 1 à 4 octets par caractère). Il faudrait donc le lire en décodant le fichier en UTF-8 également.
✎ 10° Réaliser les tâches suivantes
Mettre en mémoire, lire mentalement et utiliser le script suivant qui
crée un fichier en UTF-8 puis le ferme (sur les lignes 2-3-4)
lit ce fichier en UFT-8 puis le ferme (sur les lignes 7-8-9-10).
1
2
3
4
5
6
7
8
9
10
# 1 - Ecriture du fichierobj_fichier=open('perceval.txt','w',encoding="utf-8")obj_fichier.write("C'est écrit en UTF-8 ?\nDe toutes manières, j'ai jamais rien compris à vos histoires d'encodage.")obj_fichier.close()# 2 - lecture du fichierobj_fichier=open('perceval.txt','r',encoding="utf-8")forligneinobj_fichier:print(ligne)obj_fichier.close()
Ci-dessous le résultat attendu à l'affichage :
Affichage avec écriture en UTF-8 et lecture en UTF-8 :
C'est écrit en UTF-8 ?
De toutes manières, j'ai jamais rien compris à vos histoires d'encodage.
Fournir sur votre copie la modification suivante du programme : il doit créer le fichier en UTF-8 mais le lire en iso8859_15 (également nommée latin9 ou latin-9). Il s'agit de la table ASCII étendu (un octet) pour l'europe de l'Ouest. Fournir le code du nouveau script sur votre copie.
Affichage attendu avec écriture en UTF-8 et lecture en iso8859_15 :
Lancer le programme pour observer que votre affichage correspond bien à celui qui est représenté ci-dessus.
Les caractères de base (ceux qui ASCII) sont-ils bien lus ? Quels sont les caractères qui semblent poser problèmes lorsqu'il n'y a pas correspondance entre encodage d'écriture et encodage de lecture ?
✎ 11° Créer un script qui permet de créer un fichier-texte contenant le texte suivant en l'encodant en iso8859_15.
texte = "Ce court texte a été créé en considérant le fait qu'on a besoin de caractères peu courants lorsqu'on veut comparer les tailles obtenues avec différents encodages, à savoir le fait que la plus petite taille sera obtenue avec les tables 1 octet et la plus grande taille avec utf-32"
Vérifier que la taille du fichier-texte est de 279 octets : après création par votre programme python, faire un clic-droit sur le fichier-texte et rechercher sa taille dans les propriétés.
✎ 12° Modifier le script de façon à créer le même fichier-texte mais en utilisant différents encodages.
Questions
Quelle est la taille du fichier-texte encodé en utf-8 ?
Quelle est la taille du fichier-texte encodé en utf-16 ?
Quelle est la taille du fichier-texte encodé en utf-32 ?
Taille des fichiers-texte
Les fichiers-texte encodés en ASCII étendu pèsent un octet par caractère.
Les fichiers-texte encodés en UTF-8 pèsent à peine plus si les caractères sont principalement des fichiers ASCII.
Les fichiers-texte encodés en UTF-16 pèsent deux fois plus environ.
Les fichiers-texte encodés en UTF-32 pèsent quatre fois plus que le fichier en ASCII étendu.
rajouter des choses dans les fichiers (avec 'a') et
lire les fichiers avec (avec 'r')
Une fois lu dans Python, ces textes se retrouvent stocker dans des strings. Il est donc important de connaître quelques manipulations basiques avec des strings.
(Rappel) 4.1 STRING : mots-clés in et not in
Test d'appartenance ou de présence
On utilise l'opérateur binaire in qui renvoie un booléen.
Pour savoir si le string contenu est présent dans le string s, on tape contenuins.
>>> "bon" in "bonjour"
True>>> "Bon" in "bonjour"
False
Traduction : "bon" est-il présent dans "bonjour" ? "Bon" est-il présent dans "Bonjour" ?
Appartenance (str) : coût LINÉAIRE par rapport au nombre n de caractères.
Test de non-appartenance ou d'absence
On utilise l'opérateur binaire not in qui renvoie un booléen.
Pour savoir si le string contenu n'est pas présent dans le string s, on tape contenunot ins.
>>> "bon" not in "bonjour"
False>>> "Bon" not in "bonjour"
True
Traduction : "bon" est-il absent de "bonjour" ? "Bon" est-il absent de "Bonjour" ?
4.2 STRING : méthode endswith()
Tester si un string fini par .txt ?
C'est toujours pratique de vérifier l'extension d'un fichier.
Il existe une méthode endswith() des strings qui sert à ça :
>>> nom = 'perceval.txt'
>>> nom.endswith('.txt')
True
>>> nom.endswith('.png')
False
On peut aussi juste vérifier que les 4 derniers caractères correspondent bien à .txt.
Transformer un string en majuscules ou en minuscules ?
Pratique pour vérifier si un texte contient le nom Toto sans tester toto, TOTO et Toto...
On peut utiliser les méthodes upper et lower qui renvoie une copie du string.
Regardez bien la majuscule dans le nom suivant :
>>> nom = "Merlin ou Toto l'asticot"
>>> 'toto' in nom
False
>>> 'toto' in nom.lower()
True
>>> nom
"Merlin ou Toto l'asticot"
4.4 str → list avec list() : récupérer les caractères
Un string est un conteneur de caractères.
On peut donc les placer dans un autre conteneur, par exemple un tableau.
Pour cela, le plus simple est d'utiliser la fonction native list() qui tente de créer un tableau à partir des données fournies en entrée.
Récupérer les caractères dans un tableau
Il suffit d'utiliser la fonction native list().
>>> nom = "Merlin ou Toto l'asticot"
>>> t = list(nom)
>>> t
['M', 'e', 'r', 'l', 'i', 'n', ' ', 'o', 'u', ' ', 'T', 'o', 't', 'o', ' ', 'l', "'", 'a', 's', 't', 'i', 'c', 'o', 't']
4.5 str → list avec split() récupérer les éléments structurants d'un string
Une phrase est un ensemble de mots séparés par des espaces notamment.
La méthode split() veut dire séparer et permet justement de "séparer" un string en différentes parties et placer ces parties dans un tableau.
Récupérer les mots d'une phrase
On utilise la méthode split() en précisant que le caractère de séparation est l'espace.
>>> nom = "Merlin ou Toto l'asticot"
>>> t = nom.split(' ')
>>> t
['Merlin', 'ou', 'Toto', "l'asticot"]
Spliter sans rien fournir
Par défaut, il est possible de ne pas préciser le caractère qui servira à scinder le string en plusieurs parties : la méthode est configurée pour considérer qu'il s'agit de l'espace.
>>> nom = "Merlin ou Toto l'asticot"
>>> t = nom.split()
>>> t
['Merlin', 'ou', 'Toto', "l'asticot"]
Récupérer les phrases ?
Pour récupérer les phrases, on peut considérer qu'il suffit d'utiliser la méthode en considérant que le caractère séparateur est le point.
4.6 STRING : récupérer dans un tableau les colonnes d'une ligne CSV
Récupérer les informations dans une ligne d'un fichier CSV
Dans un fichier CSV :
chaque ligne du fichier est un enregistrement
chaque ligne est constituée d'informations séparées par des virgules ou des points-virgules.
Pour les séparer, il suffit d'utiliser la méthode split() en précisant que le caractère de séparation est le point-virgule par exemple.
>>> ligne = "Merlin;magicien;999 ans;Forêt de Brocéliande/n"
>>> t = ligne.split(';')
>>> t
['Merlin', 'magicien', '999 ans', 'Forêt de Brocéliande/n']
4.7 STRING : méthode replace()
Remplacer un caractère par un autre
Attention, on ne modifie pas le string initial (il est immmuable !). On renvoie juste une copie modifiée.
Pratique par exemple pour supprimer les /n reçus dans un string.
>>> ligne = "Merlin;magicien;999 ans;Forêt de Brocéliande/n"
>>> ligne_bis = ligne.replace("/n", "")
>>> ligne_bis
'Merlin;magicien;999 ans;Forêt de Brocéliande/n'>>> t = ligne_bis.split(";")
>>> t
['Merlin', 'magicien', '999 ans', 'Forêt de Brocéliande']
✎ 13° Réaliser les tâches suivantes :
Lancer ce programme et faire au moins trois enregistrements
fichier=open('musique.csv','a',encoding='utf-8')continuer="o"whilecontinuer.lower()!='n':titre=input("Entrer le titre de la chanson : ")artiste=input("Entrer le nom du chanteur / groupe : ")sortie=input("Date de sortie (format MM-AAAA) : ")genre=input("Genre musical : ")note=input("Votre notation (de 0 (nul) à 5 (excellent)")url=input("Obligatoire : une URL pour l'écouter ou avoir des infos")enregistrement=f"{titre};{artiste};{sortie};{genre};{note};{url}"fichier.write(enregistrement+'\n')continuer=input("Nouvelle entrée (O/N) ? ")fichier.close()
Localiser le fichier créé après être sorti de la boucle. Cliquer dessus : vous devriez voir qu'un fichier texte CSV est un format compréhensible pour un tableur.
Expliquer ce que fait ce programme étape par étape.
Analyser la ligne 5 avec précision : dans quels cas parvient-on à sortir de la boucle ? Décrire les réponses possibles permettant de sortir de la boucle.
Qu'aurions-nous pu mettre à la place de "o" en ligne 3 ?
✎ 14° Qu'est-ce que le format CSV, Comma Separated Value ?
A : Un format libre de musique, une alternative à MP3.
B : Un format texte permettant de comprimer les données.
C : Un format d'enregistrement simple de données où chaque enregistrement prend une ligne et où les éléments sont séparés par des virgules
D : Il y a une faute dans l'énoncé. C'est Coma Separated Value en réalité. C'est un format de données presque abandonné, comateux.
On demande d'enregistrer des choses. C'est fait. Mais comment les lire ?
✎ 15° Fournir un programme capable de lire et afficher ligne par ligne les enregistrements dans le fichier CSV que nous venons de créer. Vous réaliser d'abord un affichage brut de la ligne.
Modifier ensuite votre programme : en utilisant la méthode split() pour séparer les différentes informations placées sur la ligne, afficher correctement les informations de chaque morceau de musique.
Pour cela, aller lire les rappels ci-dessus dont voici un court résumé :
Cette partie ne vise qu'à vous montrer ce qu'est en réalité un fichier (texte ou pas). Rien n'est à retenir par coeur.
Vous avez certainement déjà compris le principe du fichier en tant que suite d'octets. Nous allons ici manipuler le concept pour bien l'appréhender.
Obtenir les 8 bits représentant un nombre compris entre 0 et 255
Pour obtenir la réprésentation binaire d'un nombre en Python :
>>> bin(65)
'0b1000001'
Zut, il y a un 0b au début de la réponse...
Pour supprimer les deux premiers caractères (0b) :
>>> bin(65)[2:]
'1000001'
Zut, il n'y a pas 8 caractères.
Pour imposer 8 caractères :
>>> f"{bin(65)[2:]:8}"
'1000001 '
Zut, il y a 8 caractères mais justifiés à gauche...
Pour justifier à droite :
>>> f"{bin(65)[2:]:>8}"
' 1000001'
Zut, il y a 8 caractères justifiés à droite mais avec un espace. Je veux mon 0 moi...
Pour justifier à droite ET rajouter les 0 nécessaires à gauche :
>>> f"{bin(65)[2:]:0>8}"
'01000001'
Enfin...
Nous avons vu que votre fichier n'est au final qu'une suite d'octets.
Ca tombe bien : Python est capable de lire les octets du fichier plutôt que de tenter de les interpréter-décoder sous forme d'un texte. Pour cela, il faut créer votre objet-fichier avec un argument contenant 'r', comme binaire. Ainsi pour lire les octets, il suffit d'ouvrir le fichier avec 'rb'.
Nous utiliserons deux méthodes :
la méthode read() qui permet de lire un certain nombre d'octets dans le flux.
la méthode tell() qui renvoie la position du pointeur sur le fichier.
16° Utiliser ce script qui crée un fichier en l'encodant en iso8859_15 et qui l'ouvre ensuite en lecture binaire de façon à voir le contenu octet par octet.
On utilise l'affichage Python usuel des bytes : si la valeur est inférieure à 128, on affiche le caractère ASCII correspondant.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# Création et fermeture du fichierfichier=open('lecture.txt','w',encoding="iso8859_15")fichier.write("Dernière partie.\n")fichier.close()# Ouverture du fichier en mode bytefichier=open('lecture.txt','br')# Affichage en utilisant l'affichage standard des bytes en Pythonoctet=b'0'whileoctet:position=fichier.tell()# On mesure la position du pointeur de lectureoctet=fichier.read(1)# On lit un octet dans le fluxifoctet:print(f"Position dans le fichier : {position:2}. Lecture : {bin(ord(octet))[2:]:0>8} ou {octet}")# Fermeture du fichierfichier.close()
Résultat obtenu :
Position dans le fichier : 0. Lecture : 01000100 ou b'D'
Position dans le fichier : 1. Lecture : 01100101 ou b'e'
Position dans le fichier : 2. Lecture : 01110010 ou b'r'
Position dans le fichier : 3. Lecture : 01101110 ou b'n'
Position dans le fichier : 4. Lecture : 01101001 ou b'i'
Position dans le fichier : 5. Lecture : 11101000 ou b'\xe8'
Position dans le fichier : 6. Lecture : 01110010 ou b'r'
Position dans le fichier : 7. Lecture : 01100101 ou b'e'
Position dans le fichier : 8. Lecture : 00100000 ou b' '
Position dans le fichier : 9. Lecture : 01110000 ou b'p'
Position dans le fichier : 10. Lecture : 01100001 ou b'a'
Position dans le fichier : 11. Lecture : 01110010 ou b'r'
Position dans le fichier : 12. Lecture : 01110100 ou b't'
Position dans le fichier : 13. Lecture : 01101001 ou b'i'
Position dans le fichier : 14. Lecture : 01100101 ou b'e'
Position dans le fichier : 15. Lecture : 00101110 ou b'.'
Position dans le fichier : 16. Lecture : 00001010 ou b'\n'
17° Questions :
Ligne 7 : Qu'est-ce qui montre qu'on ouvre le fichier en mode binaire et pas en mode texte ?
Ligne 10 : pourquoi créer une variable octet à cette endroit pour y mettre "n'importe quoi" ?
Combien d'octets dans ce fichier ?
...CORRECTION...
Ligne 7 : Il s'agit de l'indication 'rb' : r pour read et b pour byte.
Ligne 10 : il s'agit simplement de pouvoir rentrer une première fois dans la boucle non bornée while.
En comptant manuellement, on voit que le fichier est composé de 17 octets.
L'affichage des bytes de cette façon ne permet pas de voir clairement que ce sont juste des octets.
Nouveau programme : on affiche le contenu trois fois de suite :
Une première fois en les affichant avec le principe de Python.
Une deuxième fois en obtenant leurs valeurs en base 10
Une troisième fois en affichant leurs valeurs en base 16
Les seules différences entre les trois tient dans la façon d'afficher l'octet (voir les codes surlignés).
# Création et fermeture du fichierfichier=open('lecture.txt','w',encoding="iso8859_15")fichier.write("Dernière partie.\n")fichier.close()# Ouverture du fichier en mode bytefichier=open('lecture.txt','br')# Affichage en utilisant l'affichage standard des bytes en Pythonoctet=b'0'whileoctet:position=fichier.tell()# On mesure la position du pointeur de lectureoctet=fichier.read(1)# On lit un octet dans le fluxifoctet:print(f"Position dans le fichier : {position:2}. Lecture : {bin(ord(octet))[2:]:0>8} ou {octet}")# Affichage en affichant les valeurs décimalesoctet=b'0'whileoctet:position=fichier.tell()# On mesure la position du pointeur de lecture octet=fichier.read(1)ifoctet:print(f"Position dans le fichier : {position:2}. Lecture : {ord(octet)}")# Affichage en affichant les valeurs hexadécimalesoctet=b'0'whileoctet:position=fichier.tell()# On mesure la position du pointeur de lectureoctet=fichier.read(1)ifoctet:print(f"Position dans le fichier : {position:2}. Lecture : {hex(ord(octet))}")# Fermeture du fichierfichier.close()
Question
Pourquoi UN SEUL AFFICHAGE alors qu'on réalise trois boucles de lecture-affichage ?
...CORRECTION...
Simplement car à chaque utilisateur du read on se déplace de un octet. Au bout d'un moment, nous arrivons donc... à la fin du fichier !
Lorsqu'on arrive en ligne 21 ou 29, on est déjà en fin de fichier. La lecture ne renvoit donc rien.
Comment faire alors ? Il faut revenir en arrière. Pour cela, il existe une méthode nommée seek. On lui transmet en argument la position à laquelle on veut placer le pointeur de fichier.
Ici, on veut le remettre à zéro, revenir au début du fichier.
19° Utiliser le nouveau programme. Vous devriez cette fois obtenir trois fois le contenu du fichier.
# Création et fermeture du fichierfichier=open('lecture.txt','w',encoding="iso8859_15")fichier.write("Dernière partie.\n")fichier.close()# Ouverture du fichier en mode bytefichier=open('lecture.txt','br')# Affichage en utilisant l'affichage standard des bytes en Pythonoctet=b'0'whileoctet:position=fichier.tell()# On mesure la position du pointeur de lectureoctet=fichier.read(1)# On lit un octet dans le fluxifoctet:print(f"Position dans le fichier : {position:2}. Lecture : {bin(ord(octet))[2:]:0>8} ou {octet}")# Affichage en affichant les valeurs décimalesfichier.seek(0)octet=b'0'whileoctet:position=fichier.tell()# On mesure la position du pointeur de lecture octet=fichier.read(1)ifoctet:print(f"Position dans le fichier : {position:2}. Lecture : {ord(octet)}")# Affichage en affichant les valeurs hexadécimalesfichier.seek(0)octet=b'0'whileoctet:position=fichier.tell()# On mesure la position du pointeur de lectureoctet=fichier.read(1)ifoctet:print(f"Position dans le fichier : {position:2}. Lecture : {hex(ord(octet))}")# Fermeture du fichierfichier.close()
Position dans le fichier : 0. Lecture : 01000100 ou b'D'
Position dans le fichier : 1. Lecture : 01100101 ou b'e'
Position dans le fichier : 2. Lecture : 01110010 ou b'r'
Position dans le fichier : 3. Lecture : 01101110 ou b'n'
Position dans le fichier : 4. Lecture : 01101001 ou b'i'
Position dans le fichier : 5. Lecture : 11101000 ou b'\xe8'
Position dans le fichier : 6. Lecture : 01110010 ou b'r'
Position dans le fichier : 7. Lecture : 01100101 ou b'e'
Position dans le fichier : 8. Lecture : 00100000 ou b' '
Position dans le fichier : 9. Lecture : 01110000 ou b'p'
Position dans le fichier : 10. Lecture : 01100001 ou b'a'
Position dans le fichier : 11. Lecture : 01110010 ou b'r'
Position dans le fichier : 12. Lecture : 01110100 ou b't'
Position dans le fichier : 13. Lecture : 01101001 ou b'i'
Position dans le fichier : 14. Lecture : 01100101 ou b'e'
Position dans le fichier : 15. Lecture : 00101110 ou b'.'
Position dans le fichier : 16. Lecture : 00001010 ou b'\n'
Position dans le fichier : 0. Lecture : 68
Position dans le fichier : 1. Lecture : 101
Position dans le fichier : 2. Lecture : 114
Position dans le fichier : 3. Lecture : 110
Position dans le fichier : 4. Lecture : 105
Position dans le fichier : 5. Lecture : 232
Position dans le fichier : 6. Lecture : 114
Position dans le fichier : 7. Lecture : 101
Position dans le fichier : 8. Lecture : 32
Position dans le fichier : 9. Lecture : 112
Position dans le fichier : 10. Lecture : 97
Position dans le fichier : 11. Lecture : 114
Position dans le fichier : 12. Lecture : 116
Position dans le fichier : 13. Lecture : 105
Position dans le fichier : 14. Lecture : 101
Position dans le fichier : 15. Lecture : 46
Position dans le fichier : 16. Lecture : 10
Position dans le fichier : 0. Lecture : 0x44
Position dans le fichier : 1. Lecture : 0x65
Position dans le fichier : 2. Lecture : 0x72
Position dans le fichier : 3. Lecture : 0x6e
Position dans le fichier : 4. Lecture : 0x69
Position dans le fichier : 5. Lecture : 0xe8
Position dans le fichier : 6. Lecture : 0x72
Position dans le fichier : 7. Lecture : 0x65
Position dans le fichier : 8. Lecture : 0x20
Position dans le fichier : 9. Lecture : 0x70
Position dans le fichier : 10. Lecture : 0x61
Position dans le fichier : 11. Lecture : 0x72
Position dans le fichier : 12. Lecture : 0x74
Position dans le fichier : 13. Lecture : 0x69
Position dans le fichier : 14. Lecture : 0x65
Position dans le fichier : 15. Lecture : 0x2e
Position dans le fichier : 16. Lecture : 0xa
Regardons maintenant la différence entre un fichier encodant un texte en utilisant un table 1 octet et un fichier encodant un texte en UFT-8.
20° Utiliser ce nouveau programme. Changer ensuite l'encodage initial pour de l'utf-8. Pourquoi le fichier en UTF-8 prend-t-il plus de place en mémoire ?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# Création et fermeture du fichierfichier=open('lecture.txt','w',encoding="iso8859_15")fichier.write("Dernière partie.\n")fichier.close()# Ouverture du fichier en mode bytefichier=open('lecture.txt','br')# Affichage en affichant les valeurs décimalesoctet=b'0'whileoctet:position=fichier.tell()# On mesure la position du pointeur de lecture octet=fichier.read(1)ifoctet:print(ord(octet),end=" ")# Fermeture du fichierfichier.close()
On peut récupérer les valeurs des octets un par un en utilisant une simple boucle :
>>> octets = bytes([66, 65, 66, 65])
>>> octets
b'BABA'>>> for o in octets: print(o)
66
65
66
65
La fonction native ord() permet de convertir un octet en sa valeur entière, c'est à dire lire ses bits en le décodant comme s'il s'agissait d'un entier naturel.
Cette partie n'est pas du tout au programme. Ca va allez vite. Non pas car c'est simple mais parce qu'il y a trop à dire !.
Les expressions régulières sont un moyen de trouver des motifs dans un string.
Il faut fournir entre crochets l'ensemble des caractères qu'on recherche.
[0-9] veut dire qu'on attend un caractère numérique (0-1-2-3-4-5-6-7-8-9) et un seul.
[0-9]{2} veut dire qu'on s'attend à trouver deux chiffres : 08, 75 ou 42 sont valides mais pas 7A.
([0-9]{2}-) signale avec les parenthèses la recherche d'une séquence composée de deux chiffres suivi d'un tiret : 78- ou 12- ou 06- mais pas Av!.
Un exemple pour la recherche d'un numéro de téléphone dans un texte. Avec Python, il faut utiliser le module re.
>>> import re
>>> texte = "Le numéro de Toto l'asticot est 06-07-06-07-06..."
>>> sequence = "([0-9]{2}-){4}([0-9]{2}){1}"
On recherche donc 4 séquences chiffre chiffre tiret suivi d'une unique séquence chiffre chiffre.
>>> re.search(sequence, texte)
<re.Match object; span=(32, 43), match='06-07-06-07'>>>> if re.search(sequence, texte): print('Ce texte contient un n°')
Ce texte contient un n°>>> trouve = re.search(sequence, texte)
>>> trouve.group()
'06-07-06-07-06'
On notera que la réponse de la méthode search est un objet complexe de classe Match qui contient notamment les index du début et de la fin du motif trouvé.
On peut accéder au(x) string(s) trouvé(s) en utilisant la méthode group sur cet objet.
Dernière chose : la validation des entrées. Il ne sert à rien d'enregistrer des données sans être certain de ce qu'à rentrer l'utilisateur. Si on vous demande une date et qu'on stocke 28 juin 1995, nous allons être bien géné lorsqu'il faudra traiter les données si on voulait 06-1995.
A titre d'exemple voici comment tenter de créer un test sur la date pour ne pas enregistrer la demande si la date ne respecte pas ce format :
une séquence de 2 chiffres suivi d'un tiret ([0-9]{2}-){1},
puis une séquence de 4 chiffres ([0-9]{4}){1}.
>>> sequence = "([0-9]{2}-){1}([0-9]{4}){1}"
J'ai vu plein de programmes sur le net où on ne donne pas l'encodage.
Si on ne note pas d'encodage, l'interpréteur va le choisir pour vous !
Les versions actuelles de Python sont définies avec utf-8 comme encodage par défaut.
Noter l'encodage ne fait jamais de mal, surtout quand on débute. Cela vous permet de vous souvenir qu'on a juste des octets auxquels on donne un sens en utilisant une technique d'encodage.
J'ai vu des programmes avant des with. C'est quoi ?
Le problème du fichier ? Il faut l'ouvrir et penser à le fermer. Or, parfois, une interruption du programme peut empêcher d'atteindre l'instruction de fermeture.
Dans ce cas, il arrive parfois qu'on ne parvienne plus à ouvrir le fichier car le système pense qu'il est encore ouvert. Ou alors une modification n'a pas pu être faite correctement et le fichier est corrompu (c'est à dire qu'on ne parvient plus à décoder son contenu correctement).
Pour contourner le problème, Python propose un gestionnaire de contexte, context manager en anglais. Et son utilisation se fait en utilisant le mot-clé with.
Le principe est simple : en l'utilisant à l'ouverture, l'interpréteur s'arrange pour fermer le fichier dans tous les cas. Ce n'est pas vous qui avez à placer votre méthode close. Il s'en charge tout seul.
On voit donc qu'on utilise pas d'affectation directe. On utilise les mots-clé with et as pour faire le lien entre la variable fichier et l'instruction qui a permi de la créer open('lecture.txt','w',encoding="utf-8").
On retrouve le : et l'indentation. Dès qu'on sort de l'indentation, c'est qu'on ferme le fichier, automatiquement. C'est l'interpréteur qui s'en charge.