Apprentissage de la Programmation avec Python Corrig - FR

publicité
IGI-3008 – ESIEE Paris – 2016-2017
Figure 1 — Un extrait des tables Unicode
Apprentissage de la Programmation avec Python
Corrigé du TP4
Jean-Claude GEORGES
Retour sur les chaînes de caractères
Fonctions et méthodes
Les chaînes de caractères sont des objets indexés (dont les composants sont numérotés)
non modifiables. Outre les littéraux, on peut créer une chaîne en utilisant sa valeur Unicode
ou son nom (hélas en anglais).
Exercice 1 — Chaînes bizarres
Solution p. 7
Que contiennent les chaînes suivantes ?
>>> '\u2713'
>>> "Utilisez '\N{MULTIPLICATION SIGN}' ou '\u00d7' pour \
afficher un signe
de multiplication"
>>> "\N{WHITE SMILING FACE}"
>>> '\u0627\u0628\u0648\u062c\u0639\u0641\u0631\u0020\u0645\u062d\u0645\
\u062f\u0020\u0628\u0646\u0020\u0645\u0648\u0633\u06cc\u0020\u062e\u0648\
\u0627\u0631\u0632\u0645\u06cc'
Les listes des caractères Unicode et de leurs noms associés est disponible à l’adresse
I http://www.unicode.org/charts/ (attention, toutes les machines ne disposent pas de
tous les caractères)
Figure 2 — Les noms Unicode
FONCTIONS ET MÉTHODES
2
L’indexation s[i] permet d’extraire un caractère unique de la chaîne. La découpe (slicing)
s[d:f:p] permet de créer une nouvelle chaîne construite à partir de la chaîne de départ.
Figure 3 — Indexation et slicing
Les numérotations se font comme indiqué Fig. 3.
Exercice 2 — Indexation et slicing
Solution p. 7
Avec >>> s = "0123456789", que donneront les commandes suivantes ?
>>> s[3]
>>> s[-1]
>>> s[0]
>>> s[-3]
>>> s[40]
>>> s[-40]
>>> s[3:8]
>>> s[8:3]
>>> s[:8]
>>> s[3:]
>>> s[:]
>>> s[-8:-3]
>>> s[:-3]
>>> s[-8:]
>>> s[3:8:2]
>>> s[:8:3]
>>> s[2::2]
>>> s[::2]
>>> s[-3:-8:-2]
>>> s[-2::-3]
>>> s[:2:-3]
>>> s[::-1]
Figure 4 — Pourquoi changement de casse
On parle de casse en imprimerie, car avant les ordinateurs, les
caractères (cassetins) en plomb étaient rangés dans des caisses,
avec en bas les minuscules et en haut les majuscules.
Exercice 3 — Changement de casse
Solution p. 8
Avec >>> s = "Un EXEMPLE de Chaîne de Caractères", que donneront les commandes
suivantes ?
>>> s.lower()
>>> s.upper()
>>> s.capitalize()
>>> s.title()
>>> s.swapcase()
Corrigé du TP4
IGI-3008 (2016-2017)
FONCTIONS ET MÉTHODES
3
D’autres opérateurs, fonctions ou méthodes sont utilisables sur les chaînes.
Exercice 4 — Tests
Solution p. 8
Avec s = "Monsieur Jack, vous dactylographiez bien mieux que votre ami Wolf",
que donneront les commandes suivantes ?
>>> "Jack" in s
>>> "Jacky" in s
def inferieur(s1, s2) :
i = 0
while i < len(s1) and i < len(s2) :
if ord(s1[i]) == ord(s2[i]) : # si c1 == c2 (en Unicode)
i += 1 # on passe au suivant
continue
else : # si c1 != c2 ()en Unicode)
return ord(s1[i]) < ord(s2[i]) # c1 < c2
else : # si s1 ou s2 est terminé
return len(s1)<len(s2) # s1 doit être plus court que s2
Pour les règles de l’ordre lexicographique en français et
leur programmation, voir I http://www-clips.imag.fr/geta/
>>> "" in s
gilles.serasset/tri-du-francais.html
>>> s.startswith("monsieur")
>>> s.endswith("olf")
>>> "Python" == "Python"
>>> "Python" < "Python.3"
>>> "Python.2" < "Python.3"
>>> "Python" == "python"
>>> "Python" <= "python"
>>> "Zorro" < "cavalier"
>>> "a" < "b"
>>> "à" < "b"
>>> "a123".isalnum() ;"a12 3".isalnum()
>>> "Python".isalpha() ;"Pyth0n".isalpha()
>>> "123".isdigit() ;"12.3".isdigit() ;"-12".isdigit()
>>> "A2".isidentifier() ;"2A".isidentifier() ;
>>> "arrière-grand-mère".islower() ;"Blanche-Neige et les 7 nains".islower()
>>> "VOL 714 POUR SIDNEY".isupper() ;"VOL 714 POUR SlDNEY".isupper()
>>> " ".isprintable() ;"tabulation \t".isprintable()
>>> "\n\t ".isspace()
Corrigé du TP4
Figure 5 — Comparaisons lexicographiques
On remarque que les comparaisons sur les chaînes ne sont pas
lexicographiques (ordre du dictionnaire). Elles suivent l’ordre
Unicode. Le programme Python équivalent à la comparaison <
est le suivant :
IGI-3008 (2016-2017)
FONCTIONS ET MÉTHODES
4
Exercice 5 — Suppression/ajout/remplacement
Solution p. 9
Que donneront les commandes suivantes ?
>>> "12".zfill(5)
>>> "
\t\n suppression des espaces à gauche
>>> "
suppression des espaces à droite
\t\n ".rstrip()
".lstrip()
>>> "
suppression des espaces à droite
et à gauche
\t\n ".strip()
>>> s = "Monsieur Jack, vous dactylographiez bien mieux que votre ami Wolf"
>>> t = s.replace('ami', 'copain')
>>> print(s)
>>> print(t)
Exercice 6 — Comptage et recherche
Solution p. 9
Avec s = "Monsieur Jack, vous dactylographiez bien mieux que votre ami Wolf",
que donneront les commandes suivantes ?
len(s) ; s.count('e') ; s.count('ie')
s.find('i') ; s.find('i',40) ; s.find('i',20,30) ; s.rfind('i')
s.index('i') ; s.index('i',40) ; s.index('i',20,30)
;s.rindex('i')
Écrivez un programme qui vérifie que toutes les lettres de l’alphabet sont contenues
dans une chaîne s (qui vérifie que s est un pangramme, voir Fig. 6). On se limitera aux
chaînes en minuscules et sans accent.
Corrigé du TP4
IGI-3008 (2016-2017)
Figure 6 — Pangrammes
Un pangramme contient toutes les lettres de l’alphabet. Deux
exemples classiques :
Portez ce vieux whisky au juge blond qui fume
The quick brown fox jumps over the lazy dog.
Plus fort encore, ce pangramme de Gilles Esposito-Farèse, qui
contient toutes les lettres accentuées et ligatures du français :
Dès Noël où un zéphyr haï me vêt de glaçons würmiens, je dîne d’exquis
rôtis de bœuf au kir à l’aÿ d’âge mûr et cætera !
FONCTIONS ET MÉTHODES
5
Exercice 7 — Partitions
Solution p. 10
Que donneront les commandes suivantes ?
Figure 7 — L’aide pour la méthode partition
>>> "Une chaîne à découper".partition('à')
>>> help(str.partition)
Help on method_descriptor :
>>> "Une chaîne à découper".partition('et')
partition(...)
S.partition(sep) -> (head, sep, tail)
>>> "Une chaîne à découper".partition(' ')
Search for the separator sep in S, and return the part before it,
the separator itself, and the part after it. If the separator is not
found, return S and two empty strings.
>>> "Une chaîne à découper".split(' ')
>>> "Une chaîne à découper".split(' ',2)
>>> "Une chaîne à découper".split('e')
>>> """Un texte
Figure 8 — L’aide pour la méthode split
sur
>>> help(str.split)
Help on method_descriptor :
plusieurs
lignes""".splitlines()
>>> mots = " Une chaîne
split(...)
S.split(sep=None, maxsplit=-1) -> list of strings
à
découper en
mots
".split()
>>> mots
Return a list of the words in S, using sep as the
delimiter string. If maxsplit is given, at most maxsplit
splits are done. If sep is not specified or is None, any
whitespace string is a separator and empty strings are
removed from the result.
>>> ' '.join(mots)
Figure 9 — L’aide pour la méthode join
>>> help(str.join)
Help on method_descriptor :
join(...)
S.join(iterable) -> str
Return a string which is the concatenation of the strings in the
iterable. The separator between elements is S.
Corrigé du TP4
IGI-3008 (2016-2017)
EXERCICES DE SYNTHÈSE
6
Exercices de synthèse
Normalisation d’un mot français
On a vu dans l’exercice 4 que les comparaisons sur les chaînes de caractères ne sont pas
compatibles avec l’ordre alphabétique français.
Exercice 8 — Normalisation d’un caractère
Solution p. 10
Créez une fonction normalise_lettre qui retourne la (ou les) lettre(s) minuscule(s)
correspondant au caractère de longueur 1 passé en paramètre, les caractères non lettres
restant inchangés (’Z’ → ’z’, ’é’ → ’e’, ’œ’ → ’oe’, ’8’ → ’8’, ’ ?’ → ’ ?’ ).
Figure 10 — Diacritiques et ligatures
Il existe en français :
- 16 lettres avec diacritiques : à â ä ç é è ê ë î ï ô ö ù û ü ÿ
- 2 ligatures : æ, œ
auxquelles on peut ajouter des lettres présentes dans certains
dictionnaires pour des mots d’origine étrangère comme ñ (cañon),
å (ångström) ou ō (Tōkyō)
Exercice 9 — Normalisation d’un mot
Solution p. 10
Créez une fonction normalise_texte qui retourne la chaîne minuscule du texte passé
en paramètre, avec ses lettres accentuées ou cédillées converties en lettres normales et les
ligatures séparées (’ZÈBRE’ → ’zebre’, ’bœuf’ → ’boeuf’). Testez cette fonction avec la
chaîne suivante :
Dès Noël où un zéphyr haï me vêt de glaçons würmiens, je dîne d’exquis rôtis de bœuf au kir à l’aÿ d’âge
mûr et cætera !
Figure 11 — Quelques palindromes à tester
Engage le jeu que je le gagne.
Tu l’as trop écrasé, César, ce Port-Salut !
Saippuakivikauppias (marchand de pierre de savon en finnois)
et le plus vieux dialogue (trilogue ?) palindromique du monde :
– Madam, I’m Adam !
– Eve.
– Ssssssss...
Exercice 10 — Palindrome
Solution p. 11
Écrivez les fonctions nécessaires à vérifier qu’un texte est un palindrome.
Une erreur de transcription fait que le texte trouvé sur ce site indiqué Fig. 12 n’est pas
un palindrome : trouvez la correction à faire dans le texte pour qu’il devienne un vrai
palindrome.
Figure 12 — Un palindrome géant
Le site I http://homepage.urbanet.ch/cruci.com/lexique/
palindrome.htm nous donne le palindrome record de Georges
Perec.
Trace l’inégal palindrome ...... e mord ni la plage ni l’écart.
Georges Perec, La clôture et autre poèmes, Hachette,
1980
Corrigé du TP4
IGI-3008 (2016-2017)
SOLUTIONS
7
Solutions
Exercice 2 — Indexation et slicing (p. 2)
Exercice 1 — Chaînes bizarres (p. 1)
’X’ (le symbole de la coche)
"Utilisez ’×’ ou ’×’ pour afficher un signe de multiplication"
’©’ (un smiley)
(Al-Khuwarizmi en persan)
Corrigé du TP4
>>> s = "0123456789"
>>> # récupération d'un caractère
>>> s[3] # caractère n°3 (la numérotation commence à 0)
'3'
>>> s[-1] # caractère -1 (dernier caractère)
'9'
>>> s[0] # caractère 0 (1er car.)
'0'
>>> s[-3] # caractère -3 (3e car. à partir de la fin)
'7'
>>> s[40] # erreur
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: string index out of range
>>> s[-40] # erreur
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: string index out of range
>>> # découpe (slice) comptage de 1 en 1 (par défaut)
>>> s[3:8] # sous-chaîne de 3 inclus à 8 exclu
'34567'
>>> s[8:3] # de 8 inclus à 3 exclu (vide)
''
>>> s[:8] # du début à 8 exclu
'01234567'
>>> s[3:] # de 3 à la fin
'3456789'
>>> s[:] # du début à la fin (copie)
'0123456789'
>>> s[-8:-3] # de -8 inclus à -3 exclu
'23456'
>>> s[:-3] # du début à -3 exclu
'0123456'
>>> s[-8:] # de -8 inclus à la fin
'23456789'
>>> # découpe (slice) comptage de p en p
>>> s[3:8:2] # de 3 inclus à 8 exclu de 2 en 2
'357'
>>> s[:8:3] # du début à 8 exclu de 3 en 3
'036'
>>> s[2::2] # de 2 inclus à la fin de 2 en 2
'2468'
>>> s[::2] # du début à la fin de 2 en 2
'02468'
>>> s[-3:-8:-2] # à rebours de -3 à -8 exclu de 2 en 2
'753'
>>> s[-2::-3] # à rebours de -2 au début de 3 en 3
'852'
>>> s[:2:-3] # à rebours de la fin à 2 exclu de 3 en 3
'963'
>>> s[::-1] # à rebours de la fin au début
'9876543210'
IGI-3008 (2016-2017)
SOLUTIONS
Exercice 3 — Changement de casse (p. 2)
>>> s="Un EXEMPLE de Chaîne de Caractères"
>>> s.lower() # mise en minuscules
'un exemple de chaîne de caractères'
>>> s.upper() # mise en majuscules
'UN EXEMPLE DE CHAÎNE DE CARACTÈRES'
8
Exercice 4 — Tests (p. 3)
>>> s = "Monsieur Jack, vous dactylographiez bien mieux que votre ami Wolf"
>>> "Jack" in s ; "Jacky" in s ; "" in s
True
False
True
>>> s.startswith("monsieur") # commence par ... False car M majuscule
False
>>> s.endswith("olf") # se termine par...
True
>>> s.capitalize() # mise en majuscule de l'initiale
'Un exemple de chaîne de caractères'
>>> s.title() # mise en majuscule de l'initiale de chaque mot
'Un Exemple De Chaîne De Caractères'
>>> s.swapcase() # si quelqu'un me trouve son utilité ...
'uN exemple DE cHAÎNE DE cARACTÈRES'
Notez que la chaîne s n’est pas modifiée.
>>> "Python" == "Python" ;"Python" < "Python.3" ;"Python.2" < "Python.3"
True
True
True
>>> "Python" == "python" ;"Python" <= "python" ;"Zorro" < "cavalier"
False
True
True
>>> "a" < "b" ;"à" < "b"
True
False
>>> "a123".isalnum() ;"a12 3".isalnum()
True
False
>>> "Python".isalpha() ;"Pyth0n".isalpha()
True
False
>>> "123".isdigit() ;"12.3".isdigit() ;"-12".isdigit()
True
False
False
>>> "A2".isidentifier() ;"2A".isidentifier() ;
True
False
>>> "arrière-grand-mère".islower() ;"Blanche-Neige et les 7 nains".islower()
True
False
>>> "VOL 714 POUR SIDNEY".isupper() ;"VOL 714 POUR SlDNEY".isupper()
True
False
>>> " ".isprintable() ;"tabulation \t".isprintable()
True
False
>>> "\n\t ".isspace()
True
Corrigé du TP4
IGI-3008 (2016-2017)
SOLUTIONS
Exercice 5 — Suppression/ajout/remplacement (p. 4)
>>> "12".zfill(5) #} remplissage par des 0
'00012'
>>> "
\t\n suppression des espaces à gauche ".lstrip()
'suppression des espaces à gauche '
>>> "
suppression des espaces à droite \t\n ".rstrip()
'
suppression des espaces à droite'
>>> "
suppression des espaces à droite et à gauche \t\n ".strip()
'suppression des espaces à droite et à gauche'
>>> s = "Monsieur Jack, vous dactylographiez bien mieux que votre ami Wolf"
>>> t = s.replace('ami', 'copain')
>>> print(s)
Monsieur Jack, vous dactylographiez bien mieux que votre ami Wolf
>>> print(t)
Monsieur Jack, vous dactylographiez bien mieux que votre copain Wolf
Notez que la chaîne initiale n’est pas modifiée, c’est une nouvelle chaîne qui
est créée.
9
Exercice 6 — Comptage et recherche (p. 4)
>>>
>>>
65
>>>
6
>>>
4
s = "Monsieur Jack, vous dactylographiez bien mieux que votre ami Wolf"
len(s)
>>>
4
>>>
42
>>>
-1
>>>
59
s.find('i') # place du premier 'i' rencontré (-1 si absent)
s.count('e') # nombre de 'e'
s.count('ie') # nombre de 'ie'
s.find('i',40) # place du premier 'i' rencontré à partir de la position 40
s.find('i',20,30) # place du premier 'i' entre 20 inclus et 30 exclu
s.rfind('i') # comme find, mais à rebours
>>> s.index('i') # comme "find" mais erreur si absent
4
>>> s.index('i',40)
42
>>> s.index('i',20,30)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: substring not found
>>> s.rindex('i') # comme index, mais à rebours
59
>>> def pangramme(s):
...
alphabet = "abcdefghijklmnopqrstuvwxyz"
...
for x in alphabet:
...
if x not in s:
...
return False
...
else:
...
return True
...
>>> pangramme("portez ce vieux whisky au juge blond qui fume")
True
>>> pangramme("portez ce vieux whisky au juge blond qui boit")
False
Corrigé du TP4
IGI-3008 (2016-2017)
SOLUTIONS
10
Exercice 7 — Partitions (p. 5)
Exercice 8 — Normalisation d’un caractère (p. 6)
>>> "Une chaîne à découper".partition('à')
('Une chaîne ', 'à', ' découper')
>>> "Une chaîne à découper".partition('et')
('Une chaîne à découper', '', '')
>>> "Une chaîne à découper".partition(' ')
('Une', ' ', 'chaîne à découper')
>>> "Une chaîne à découper".split(' ')
['Une', 'chaîne', 'à', 'découper']
>>> "Une chaîne à découper".split(' ',2) # 2 coupures maxi.
['Une', 'chaîne', 'à découper']
>>> "Une chaîne à découper".split('e')
['Un', ' chaîn', ' à découp', 'r']
>>> """Un texte
... sur
... plusieurs
... lignes""".splitlines()
['Un texte', 'sur', 'plusieurs', 'lignes']
>>> mots = " Une chaîne
à
découper en
mots
>>> mots
['Une', 'chaîne', 'à', 'découper', 'en', 'mots']
>>> ' '.join(mots)
'Une chaîne à découper en mots'
".split()
partition retourne systématiquement un triplet : (tête,séparateur,queue),
avec séparateur et queue éventuellement vides ('').
split retourne une liste éventuellement vide : [partie1, partie2,...] et
perd les séparateurs.
join est l’opération inverse de split . Elle recolle les morceaux d’une séquence
de chaînes de caractères à l’aide du séparateur sur lequel elle porte.
split et partition ont leurs équivalents à rebours : rsplit et rpartition.
Corrigé du TP4
def normalise_lettre(c):
""" normalisation d'une lettre minuscule"""
if 'a' <= c <= 'z' or not c.isalpha(): # double inégalité légale en Python
return c # c et une référence
elif c in "àâ":
return 'a'
elif c in "æ":
return "ae"
elif c in "ç":
return 'c' # 'c' est une constante caractère
elif c in "èéêë":
return 'e'
elif c in "îï":
return 'i'
elif c in "ô":
return 'o'
elif c in "ùûü":
return 'u'
elif c in "ÿ":
return 'y'
elif c in "œ":
return "oe"
else:
return "Erreur : on ne devrait jamais passer par là"
Exercice 9 — Normalisation d’un mot (p. 6)
def normalise_texte(s):
res = ""
for x in s.lower():
res+=normalise_lettre(x)
return res
IGI-3008 (2016-2017)
SOLUTIONS
11
Exercice 10 — Palindrome (p. 6)
def palindrome(s):
""" retourne (-1, len(s)) si le texte est un palindrome
(i,j) où s{i]!=s[j] si le texte n'est pas un palindrome
"""
s = normalise(s)
i, j = 0, len(s)-1
while i<j:
if not s[i].isalpha():
i += 1
continue
if not s[j].isalpha():
j -= 1
continue
if s[i]!=s[j]:
return (i, j)
i += 1
j -= 1
return (-1, len(s))
>>> s = """ 9691 ,EDNA' D NILUOM UA ...Andé, 1969"""
>>> s = normalise(s)
>>> palindrome(s)
(881, 6860)
En affichant le texte autour du caractère 880, on peut lire : ce noir Belzebuth, ô
il offensé, tire !. Autour du caractère 6860, on peut lire Nef ! Folie ! Oh, tubez. On
voit que le transcripteur aurait dû écrire : ce noir Belzebuth, oeil offensé, tire !
Avec cette modification :
>>> palindrome(s)
(-1, 7750)
Corrigé du TP4
IGI-3008 (2016-2017)
Téléchargement