TD F1 : lecture / écriture dans un fichier texte¶
On s’intéresse dans ce chapitre aux Entrées/Sorties fichier, autrement dit à la lecture ou à l'écriture d’un fichier. En effet, lorsque l'on souhaite sauvegarder des informations et les récupérer entre diverses sessions, il est indispensable de pouvoir les transférer depuis la mémoire vive (RAM) vers un support physique (type disque dur). Il y a de nombreuses façon de procéder, et on se contentera ici d'utiliser une méthode universelle par le biais de lecture/écriture de fichiers en mode texte.
Remarque :
- on se servira beaucoup des listes dans ce TD. Si vous n'êtes pas parfaitement au clair, ou si vous voulez tout savoir (ou presque) sur ce type, aller par exemple lire les pages correspondantes sur W3school.
- on utilisera aussi les dictionnaires. Il n'y a rien sur coding game, mais si les cours n'ont pas suffit, vous pouvez consulter le site W3school.
I. Écriture dans un fichier¶
1. Un premier exemple pour voir si tout fonctionne¶
Q1. En utilsant le cours, écrire une fonction save_my_list(nomfich : str, datas : list) qui reçoit deux arguments. Le premier est un nom de fichier, le deuxième une liste de chaînes de caractères. La fonction doit écrire dans le fichier nomfich les chaînes contenues dans la liste datas (une chaine par ligne).
Pour visualiser le fichier ainsi crée :
cliquer sur le menu Capytale (en haut à gauche), puis suivre Fichiers annexes puis Disponibles le temps de la session, choisir alors le fichier test.txt et cliquer sur télécharger. Le fichier est alors sauvegardé dans votre espace personnel sur le disque dur de l'ordinateur.
Ouvrez ce fichier avec un éditeur classique (style bloc note ou notepad ...) et consultez son contenu en vérifiant qu'il est conforme aux attentes.
def save_my_list(nomfich : str,datas : list):
"""
Reçoit un nom de fichier et une liste de données (chaque élément étant une
chaîne de caractères terminée par le symbole de retour à la ligne \n),
et sauvegarde ces données dans un fichier sur le disque dur
"""
with open(nomfich, mode='w') as myfile : # on note mode='w' pour écriture
myfile.writelines(datas)
print(f"le fichier '{nomfich}'' a été créé")
# On teste :
lst = [
'Une première ligne\n'
'Une deuxième ligne\n'
'Une troisième sans le caractère de fin de ligne'
'pour voir comment apparait la dernière ligne'
]
print(lst)
save_my_list(nomfich='test.txt', datas=lst)
['Une première ligne\nUne deuxième ligne\nUne troisième sans le caractère de fin de lignepour voir comment apparait la dernière ligne'] le fichier 'test.txt'' a été créé
2. Pour s'exercer : écriture d'une table de mutiplications¶
L'objectif de cet exercice est d'obtenir un fichier texte représentant la table de multiplication des entiers de 1 à 10 sous cette forme (pour l'instant on n'affiche pas les en-têtes):
txt
1 2 3 ... 10
2 4 6 ... 20
3 6 9 ... 30
...
10 ... 100
La version chaine de caractères commencerait ainsi (visualiser les caractères \t et \n):
txt
"1\t2\t3 ... 10\t\n2\t4\t ..."
Étape 1 : création des données
Q2. Écrire une fonction multiples(n : int)->str qui reçoit un entier n et qui renvoie une chaine de caractères contenant les 10 premiers mutliples de n. Par exemple, si elle reçoit le nombre 3, la fonction doit renvoyer la chaine :
'3\t6\t9\t12\t15\t18\t21\t24\t27\30\n'
On utilisera la fonction str(...) pour convertir des nombres en chaine, et on n'oubliera pas d'insérer les caractères \t pour créer des tabulations entre les valeurs et le \n à la fin pour le retour à la ligne.
def multiples(n : int) -> str :
""" reçoit un entier `n` et qui renvoie une chaine de caractères contenant les 10 premiers mutliples de `n`
Par exemple, si elle reçoit le nombre 3, la fonction doit renvoyer la chaine :
'3\t6\t9\t12\t15\t18\t21\t24\t27\30\n'
"""
chaine = ''
for i in range(1,10):
chaine = chaine + str(n*i) + '\t'
chaine = chaine + str(n*10) + '\n'
return chaine
# on teste
print(multiples(3))
3 6 9 12 15 18 21 24 27 30
Q3. Écrire une fonction table(n : int) -> str qui reçoit un entier n et qui renvoie une chaine de caractère contenant la table de multiplication des entiers de 1 à n avec le format précédent...
(On pensera à utiliser la fonction multiples(...) créee à la question précédente...)
def table(n : int) -> str :
""" reçoit un entier n et renvoie une chaine de caractères
représentant la table de multiplication des entiers 1 à n"""
table_mult = ''
for i in range(1,n+1):
table_mult = table_mult + multiples(i)
return table_mult
# on teste
print(table(5))
1 2 3 4 5 6 7 8 9 10 2 4 6 8 10 12 14 16 18 20 3 6 9 12 15 18 21 24 27 30 4 8 12 16 20 24 28 32 36 40 5 10 15 20 25 30 35 40 45 50
Étape 2 : écriture du fichier sur le disque dur
Q4. Compléter le code de la fonction save_table(n : int) -> None qui doit créer un fichier nommé table_mult.txt dont le contenu est la table de multiplication des entiers de 1 à n sous la forme demandée par l'énoncé.
def save_table(n : int):
"""
Crée le fichier 'table_mult.txt' qui représente la table de multiplication
"""
tab = table(n)
with open('table_mult.txt', mode = 'w') as file :
file.write(tab)
print(f"fichier table_mult.txt crée avec succès")
# on teste :
save_table(10)
# pour voir le résultat : télécharger le fichier crée en allant comme au début du TD dans
# le menu 'Capytale' -> 'fichiers annexes' -> 'disponibles le temps de la session'
fichier table_mult.txt crée avec succès
Q6 (facultatif, pour aller un peu plus loin !) Pour ceux qui ont le temps, on va améliorer un peu la présentation. Écrire une fonction save_tableX_2() qui améliore le fichier texte pour obtenir quelque chose comme cela :
def save_tableX_2()->list:
"""
Crée le fichier 'table_mult2.txt' qui représente la table de multiplication raffinée
"""
# ... à completer ...
save_tableX_2()
# aller voir dans le menu capytale pour télécharger le fichier...
II. Lecture d'un fichier¶
Pour ouvrir un fichier en lecture le principe est le même que pour l'écriture mais on modifie la variable mode pour passer en lecture : mode='r' (r pour read).
II.1. Lecture d'un fichier en entier ¶
Q7 En utilisant le cours, compléter la fonction suivante qui permet de récupérer le contenu du fichier test.txt crée en début de TD.
def read_myfile1(nomfich : str) -> str :
"""
récupère et renvoie la chaine de caractères contenue dans le fichier
nommé 'nomfich'
"""
with open(nomfich,mode='r') as f :
txt = f.read()
return txt
# on teste :
print(read_myfile1('test.txt'))
Une première ligne Une deuxième ligne Une troisième sans le caractère de fin de lignepour voir comment apparait la dernière ligne
II.2 Lecture d'un fichier ligne par ligne¶
Q8. Utiliser le cours pour compléter la fonction ci-dessous dont le rôle est précisé dans la docstring
def read_myfile2(nomfich):
""" reçoit un nom de fichier 'nomfich' et renvoie le contenu
de ce fichier sous forme d'une liste de chaîne de caractères
(chaque élément de la liste contient une ligne du fichier texte)
Remarque :
Les lignes commençant par # ainsi quel les lignes vides
doivent être exclues"""
datas = []
with open(nomfich,mode='r') as f :
for line in f :
if line[0] not in ['#', '\n'] :
datas.append(line.strip())
# Remarque : la méthode 'strip' ci-dessus permet d'enlever les caractères spéciaux
# en début et fin de chaine (ici notamment le `\n')
return datas
# on teste :
datas = read_myfile2('test.txt')
print(datas)
['Une première ligne', 'Une deuxième ligne', 'Une troisième sans le caractère de fin de lignepour voir comment apparait la dernière ligne']
En français, lorsque l'on vous demande de faire un résumé, on vous impose souvent un nombre de mots. Voyons comment automatiser cette tâche en python.
Pour faire simple (mais pas totalement juste...), on va considérer que les mots dans un texte sont séparés par l'un des caractères contenus dans la liste separateurs = ["'"," ","\n"] ('apostrophe', 'espace' et '\n' qui on on le rappelle représente le caractère de retour à la ligne). On n'a pas mis par exemple la virgule ou le point car ceux-ci doivent en principe être suivis d'un espace...
On rappelle deux informations qui peuvent être utiles:
on peut tester l'apartenance d'un élément à une liste avec l'opérateur
in. Par exemple sixest une variable de typestretsune liste de chaines, alors l'instructionx in srenvoieTruesixest dans la liste etFalsesinon.une chaîne de caractères est un itérable, c'est à dire que l'on peut par exemple utiliser une boucle
forpour parcourir tous ses caractères.
L'objectif de cet exercice est de récupérer le contenu d'un texte et compter (approximativement) le nombre de mots qu'il contient.
Q9. En utilisant la fonction read_myfile1 de la Q7 du paragraphe II.1 lecture d'un fichier en entier, éctrire un script pour afficher le contenu du fichier star_wars.txt.
# affiche le contenu du texte 'stra_wats.txt'
txt = read_myfile1('star_wars.txt')
print(txt)
Il y a bien longtemps, dans une galaxie lointaine, très lointaine... La République Galactique est en pleine ébullition. La taxation des routes commerciales reliant les systèmes éloignés provoque la discorde. Pour régler la question, la cupide Fédération du Commerce et ses redoutables vaisseaux de guerre imposent un blocus à la petite planète Naboo. Face à ce dangereux engrenage, alors que le Congrès de la République s’enlise dans des débats sans fin, le Chancelier Suprême charge en secret deux Chevaliers Jedi, gardiens de la paix et de la justice dans la galaxie, de résoudre le conflit... L'agitation règne au Sénat Galactique. Des milliers de systèmes solaires ont annoncé leur intention de quitter la République. Confrontés à ce mouvement séparatiste mené par le Comte Dooku, les Chevaliers Jedi, en nombre limité, ont du mal à maintenir la paix et l'ordre dans la galaxie. La sénatrice Amidala, ancienne reine de Naboo, revient au Sénat Galactique participer à un vote crucial sur la création d'une Armée de la République pour aider les Jedi débordés... C'est la guerre ! La République croule sous les attaques de l'impitoyable Sith, le Comte Dooku. Il y a des héros dans les deux camps. Le Mal est partout. Avec une audace stupéfiante, le Général Grievous, diabolique chef droïde, est entré dans la capitale pour enlever le Chancelier Palpatine, Chef Suprême du Sénat Galactique. Alors que l'Armée Séparatiste Droïde tente de quitter la capitale assiégée avec son précieux otage, deux Chevaliers Jedi mènent une mission désespérée pour secourir le Chancelier captif...
Q10. Écrire une fonction nb_words(text : str) -> int qui reçoit un texte (type str) et qui renvoie le nombre de mots.
def nb_words(text : str) -> int:
"""
Compte le nombres de mots contenus dans la chaine 'text'
"""
separateurs = ["'", " ", "\n"]
nb = 1
for car in text :
if car in separateurs :
nb += 1
return nb
# on teste :
print(nb_words('Bonjour les amis'))
3
Q11. Compter le nombre de mots du texte star_wars.txt
Réponse : # à compléter
Comparer à ce que vous donne un logiciel tel que word ou libre office pour voir...
# nb de mots du texte 'stra_wars.txt'
txt = read_myfile1('star_wars.txt')
print(f"Dans le texte 'star_wars.txt' il y a (approximativement) {nb_words(txt)} mots.")
Dans le texte 'star_wars.txt' il y a (approximativement) 273 mots.
III.2 Palindromes¶
L'objectif de cet exercice est de compter le nombres de palindromes dans la langue française.
Q12. En vous inspirant du TD D2 (boucles for), écrire une fonction palindrome(mot : str) -> boolean qui reçoit une chaine de caractère et qui renvoie True si c'est un palindrome et False sinon.
def palindrome(mot : str) -> bool :
""" reçoit une chaine et renvoie True si c'est un palindrome et False sinon"""
for i in range(0,len(mot)):
if mot[i] != mot[-i-1] :
return False
return True
# on teste :
print(palindrome("abcdef"))
print(palindrome("abccba"))
print(palindrome("abcba"))
False True True
Q13. Lié à cette activité vous trouverez un fichier nommé liste_francais_gutemberg_conv.txt qui contient (à peu près) tous les mots de la langue française (un mot par ligne).
Écrire une fonction dictionnaire() -> list qui va lire ce fichier et renvoyer la liste de tous les mots.
def dictionnaire() -> list :
""" récupère tous les mots du fichier 'liste_francais_gutemberg_conv.txt' et
les stoke dans une liste (en enlevant les caractères spéciaux de début et de fin)"""
return read_myfile2('liste_francais_gutemberg_conv.txt')
print(dictionnaire()[:50]) # on n'affiche que les 50 premiers mots
['a', 'à', 'abaissa', 'abaissable', 'abaissables', 'abaissai', 'abaissaient', 'abaissais', 'abaissait', 'abaissâmes', 'abaissant', 'abaissante', 'abaissantes', 'abaissants', 'abaissas', 'abaissasse', 'abaissassent', 'abaissasses', 'abaissassiez', 'abaissassions', 'abaissât', 'abaissâtes', 'abaisse', 'abaissé', 'abaissée', 'abaissées', 'abaisse-langue', 'abaissement', 'abaissements', 'abaissent', 'abaisser', 'abaissera', 'abaisserai', 'abaisseraient', 'abaisserais', 'abaisserait', 'abaisseras', 'abaissèrent', 'abaisserez', 'abaisseriez', 'abaisserions', 'abaisserons', 'abaisseront', 'abaisses', 'abaissés', 'abaisseur', 'abaisseurs', 'abaissez', 'abaissiez', 'abaissions']
Q14. Écrire enfin un script python qui affiche le nombre de mots contenus dans ce fichier, ainsi que tous les palindromes qu'il contient et leur nombre.
lst = dictionnaire()
liste_palindromes = []
for mot in lst :
if palindrome(mot) :
liste_palindromes.append(mot)
print(f"Il y a {len(lst)} mots dans le dictionnaire")
print(f"On y trouve {len(liste_palindromes)} palindromes, qui sont :")
print(liste_palindromes)
Il y a 336531 mots dans le dictionnaire On y trouve 52 palindromes, qui sont : ['a', 'à', 'alla', 'ana', 'ara', 'aviva', 'axa', 'bob', 'cc', 'elle', 'erre', 'essayasse', 'esse', 'été', 'étêté', 'eue', 'gag', 'ici', 'kayak', 'lebel', 'nanan', 'non', 'pep', 'pop', 'radar', 'ressasser', 'retâter', 'rotor', 'sagas', 'salas', 'sanas', 'sapas', 'sas', 'sassas', 'selles', 'semâmes', 'sénés', 'sennes', 'serres', 'ses', 'sexes', 'shahs', 'sis', 'snobons', 'solos', 'sonos', 'sus', 'tâtât', 'tôt', 'tut', 'tût', 'y']