Exo Strings

Identification

Infoforall

18 - Exercices Str


Tous les exercices sont corrigés.

Attention : lire une correction ne garantit pas de pouvoir refaire l'exercice. Comprendre et faire sont deux capacités différentes.

1 - Manipulations basiques

01° Observer les instructions tapées sur la console Python et trouver les résultats qu'elles devraient afficher. Vérifier en tapant réellement les instructions ensuite.

>>> s = "Ceci est un exercice" >>> s[0] ??? >>> s[3] ??? >>> s[4] ??? >>> len(s) ???

...CORRECTION...

>>> s = "Ceci est un exercice" >>> s[0] 'C' >>> s[3] 'i' >>> s[4] ' ' >>> len(s) 20

02° Parmi les instructions précédentes, quelles sont celles qui montrent clairement que l'espace est un caractère comme un autre ?

...CORRECTION...

Les deux instructions ci-dessous :

  • La première car on extrait bien un espace sur la case d'indice 4.
  • Le fait que la longueur du string tienne compte des espaces et pas que des lettres.
>>> s[4] ' ' >>> len(s) 20

03° Ces questions portent sur la valeur d'indice maximale et sur l'interaction avec range.

  • Quelles seront les valeurs prises successivement par la variable de boucle i sur l'exemple ci-dessous ?
  • 012345678901234567890 >>> s = "Ceci est un exercice" >>> len(s) 20 >>> for i in range(len(s)): print(i) ???
  • Que se passerait-il si on tapait ceci ?
  • >>> s[len(s)]
  • Pourquoi est-il bien pratique en fin de compte que lorsqu'on tape for i in range(len(s)), la valeur finale de la variable de boucle i soit définie avec exclusion sur la valeur de fin ?
  • Que va-t-on obtenir sur la console avec la dernière demande ?
  • 012345678901234567890 >>> s = "Ceci est un exercice" >>> s[len(s)-1] ???

...CORRECTION...

  • La variable de boucle prendra progressivement les valeurs 0, puis 1... jusqu'à 19.
  • 012345678901234567890 >>> s = "Ceci est un exercice" >>> for i in range(len(s)): print(i) 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
  • Cela provoque une erreur puisque l'indice 20 n'existe pas. Les indices du string sont dans l'intervalle [0;19] avec les deux bornes incluses. On pourrait noter cet intervalle [0;20[ pour indiquer que le 20 est exclu.
  • >>> s[len(s)] IndexError: string index out of range
  • C'est très pratique puisque qu'en tapant for i in range(len(s)), on a donc range(len(s)) qui va être équivalent à range(20) et donc on aura un intervalle [0; 19] évitant le 20 qui serait problématique car inexistant ! Donc c'est bien pratique cette histoire de valeur finale exclue avec range.
  • Cette écriture permet d'obtenir la dernière valeur.
  • 012345678901234567890 >>> s = "Ceci est un exercice" >>> s[len(s)-1] 'e'

04° Voici une façon d'obtenir les dernières cases d'un string ou d'un tableau. Attention : dans certains langages de programmation cela fonctionne, dans d'autres les indices -1, -2... provoquent des erreurs.

Question :

Donner les évaluations des instructions suivantes. Vérifier ensuite sur la console.

012345678901234567890 >>> s = "Ceci est un exercice" >>> s[-1] ??? >>> s[-2] ??? >>> s[-3] ???

En C, C++ ou Arduino cela provoque une erreur par exemple. Attention.

...CORRECTION...

012345678901234567890 >>> s = "Ceci est un exercice" >>> s[-1] 'e' >>> s[-2] 'c' >>> s[-3] 'i'

2 - Boucle FOR avec actions via les indices

05° Que va contenir successivement la variable de boucle i dans le programme ci-dessous ? Que va afficher le programme ?

1 2 3 4
s = "bonjour" for i in range(len(s)): print(i)

...CORRECTION...

La variable de boucle i va contenir les indices successifs possibles dans le string s.

i va donc prendre successivement les valeurs 0, 1, 2... jusqu'au dernier tour de boucle où sa valeur sera 6.

Le programme va donc afficher les valeurs 0, 1, 2... jusqu'au dernier tour de boucle où il affichera 6.

06° Que va contenir successivement la variable de boucle i dans le programme ci-dessous ? Que va afficher le programme ? La seule différence se situe sur la ligne 4.

1 2 3 4
s = "bonjour" for i in range(len(s)): print(s[i])

...CORRECTION...

La variable de boucle i va contenir les indices successifs possibles dans le string s.

i va donc prendre successivement les valeurs 0, 1, 2... jusqu'au dernier tour de boucle où sa valeur sera 6.

La différence est qu'ici l'affichage concerne s[i], soit en français "Le caractère placé à l'indice i dans le string s".

On va donc d'abord afficher s[0], soit "b".

Lors du tour de boucle suivant, on va afficher s[1], soit "o".

Lors du tour de boucle suivant, on va afficher s[2], soit "n".

Puis "j"...

Jusqu'à afficher le dernier caractère s[6], soit "r".

07° Compléter le programme pour qu'on puisse parvenir à compter le nombre de questions dans le string fourni. Il suffit donc de compter le nombre de points d'interrogation.

PRECONDITON : on fournit un string contenant une phrase bien construite où chaque phrase finit par un point, un point d'exclamation ou un point d'interrogation.

1 2 3 4 5 6 7 8 9 10 11 12 13
texte1 = "Ceci est une phrase ? Ici, voici une deuxième phrase ! Et là, nous ne pourrons pas détecter la phrase car elle ne finit pas par un point" def nb_de_questions(s): '''Renvoie le nombre de questions détectées dans le string s''' nb = ... for i in range(len(...)): if ... == '?': nb = ... + ... return ... print(nb_de_questions(texte1))

...CORRECTION...

1 2 3 4 5 6 7 8 9 10 11 12 13
texte1 = "Ceci est une phrase ? Ici, voici une deuxième phrase ! Et là, nous ne pourrons pas détecter la phrase car elle ne finit pas par un point" def nb_de_questions(s): '''Renvoie le nombre de questions détectées dans le string s''' nb = 0 for i in range(len(s)): if s[i] == '?': nb = nb + 1 return nb print(nb_de_questions(texte1))

08° Répondre aux questions proposées qui correspondent à des questions d'analyse du programme ci-desous.

  1. A quoi sert la ligne 6 ? Un humain a-t-il besoin de cette étape ?
  2. La variable s est-elle un paramètre où un argument ?
  3. Lors de la déclaration et mise en mémoire de la fonction, s contient-elle quelque chose ?
  4. Sur quelle ligne se trouve l'appel de la fonction nb_de_questions() ?
  5. Quel est alors l'argument envoyé (qui sera donc stocké dans le paramètre s) ?
  6. Donner la phrase en français qui correspond à ce qu'on demande en ligne 7.
  7. Donner la phrase en français qui correspond à ce qu'on demande en ligne 8.
  8. Donner la phrase en français qui correspond à ce qu'on demande en ligne 9.
1 2 3 4 5 6 7 8 9 10 11 12 13
texte1 = "Ceci est une phrase. Ici, voici une deuxième phrase ! Et là, nous ne pourrons pas détecter la phrase car elle ne finit pas par un point" def nb_de_questions(s): '''Renvoie le nombre de questions détectées dans le string s''' nb = 0 for i in range(len(s)): if s[i] == '?': nb = nb + 1 return nb print(nb_de_questions(texte1))

...CORRECTION...

  1. A quoi sert la ligne 6 ? Un humain a-t-il besoin de cette étape ?
  2. Elle sert à initialiser le compteur. Un humain pourrait en créer spontanément en ligne 9 lorsqu'il en a besoin la première fois, mais on doit faire cette demande avant la ligne 9, sinon il y aurait un arrêt du programme à cause de la présence d'une variable non définie.

  3. La variable s est-elle un paramètre où un argument ?
  4. C'est un Paramètre car elle apparaît dans le Prototype.

  5. Lors de la déclaration et mise en mémoire de la fonction, s contient-elle quelque chose ?
  6. Non puisque c'est un paramètre : il s'agit juste d'une variable qui va permettre de recevoir les données qu'on va envoyer à notre fonction lorsqu'on va réellement en faire appel.

  7. Sur quelle ligne se trouve l'appel de la fonction nb_de_questions() ?
  8. Sur la ligne 13 : print(nb_de_questions(texte1)).

  9. Quel est alors l'argument envoyé (qui sera donc stocké dans le paramètre s) ?
  10. Il suffit de comparer le prototype et l'appel :

    Prototype ligne 3 : def nb_de_questions(s):.

    Appel ligne 13 : print(nb_de_questions(texte1)).

    On voit bien qu'on envoie l'argument texte1 lors de cet appel et qu'on va alors le ranger dans le paramètre nommé s.

  11. Donner la phrase en français qui correspond à ce qu'on demande en ligne 7.
  12. Tour à tour pour chaque indice i possible dans le string s.

  13. Donner la phrase en français qui correspond à ce qu'on demande en ligne 8.
  14. Si le caractère placé à l'indice i correspond bien à un point d'interrogation, alors réalise les instructions tabulées situées juste en dessous.

  15. Donner la phrase en français qui correspond à ce qu'on demande en ligne 9.
  16. Incrémente la variable nb de 1.

09° Quelqu'un veut utiliser la fonction nb_de_phrases() pour compter les phrases. Il veut compter le nombre de points, points d'exclamation et points d'interrogation. Son programme ne fonctionne pas.

  1. Expliquer pourquoi cette fonction ne répond pas correctement.
  2. Corriger la fonction pour qu'elle réponde correctement.

PRECONDITON : on fournit un string contenant une phrase bien construite où chaque phrase finit par un point, un point d'exclamation ou un point d'interrogation.

1 2 3 4 5 6 7 8 9 10 11 12 13
texte1 = "Ceci est une phrase. Ici, voici une deuxième phrase ! Et là, nous ne pourrons pas détecter la phrase car elle ne finit pas par un point" def nb_de_phrases(s): '''Renvoie le nombre de phrases détectées dans le string s''' nb = 0 for i in range(len(s)): if s[i] == '.' or '?' or '!': nb = nb + 1 return nb print(nb_de_phrases(texte1))

...CORRECTION...

Cette fonction ne fonctionne pas à cause de la ligne 8. Elle ne veut pas dire ce que pense le développeur qui l'a tapé.

8
if s[i] == '.' or '?' or '!':

Telle qu'elle est là, cette instruction veut dire : réalise les instructions situées en dessous SI l'une des conditions suivantes est évaluée à VRAI :

  • s[i] == '.', ce qui veut bien dire si le caractère est un point.
  • ou '?', ce qui veut dire si '?' est évaluée à VRAI. Et ceci est toujours VRAI puisqu'en Python, les seules choses évaluées à FAUX sont 0, None, le string vide "", le tableau vide []... Cette expression ne veut donc pas dire DU TOUT ce que pensait le développeur.
  • ou '!', idem cette expression sera toujours évaluée à VRAI si on cherche à l'évaluer sous forme d'un booléen.

Ce test ne sert donc à rien. C'est comme si on avait tapé if True.

Ce qu'il faut vraiment tapé pour que l'ordinateur comprenne ce qu'on désire est :

8
if s[i] == '.' or s[i] == '?' or s[i] == '!':

10° Quelqu'un propose cette version plus courte de la fonction nb_de_phrases(). Elle est valide également.

Expliquer en français ce que veut dire la ligne 8.

1 2 3 4 5 6 7 8 9 10 11 12 13
texte1 = "Ceci est une phrase. Ici, voici une deuxième phrase ! Et là, nous ne pourrons pas détecter la phrase car elle ne finit pas par un point" def nb_de_phrases(s): '''Renvoie le nombre de phrases détectées dans le string s''' nb = 0 for i in range(len(s)): if s[i] in ".?!": nb = nb + 1 return nb print(nb_de_phrases(texte1))

...CORRECTION...

La ligne 8 veut au final dire la même chose que la version précédente. On utilise juste une "Pythonnerie" qui réalise en sous-main le travail que nous avions écrit dans la version précédente.

8
if s[i] in ".?!":

Cela veut dire : Si le caractère lu à l'indice i se trouve dans la chaine de caractère ";?!".

En réalité, lorsque tape ceci, cela revient bien en terme de logique à effectuer ceci puisque s[i] n'est composé que d'un seul caractère :

8
if s[i] == '.' or s[i] == '?' or s[i] == '!':

11° Quelqu'un vous demande de lui expliquer ligne par ligne la fonction voyelles_majuscules qui se propose de renvoyer un string où toutes les voyelles sont transformées en majuscules.

1 2 3 4 5 6 7 8 9 10 11 12
texte1 = "Ceci est une phrase. Ici, voici une deuxième phrase ! Et là, nous ne pourrons pas détecter la phrase car elle ne finit pas par un point" def voyelles_majuscules(s): '''Renvoie une version du string où les voyelles sont en majuscules''' t = list(s) for i in range(len(t)): if t[i] in "aeéèyuio": t[i] = t[i].upper() return "".join(t) print(voyelles_majuscules(texte1))

Ce programme provoque l'affichage suivant :

CEcI Est UnE phrAsE. IcI, vOIcI UnE dEUxIÈmE phrAsE ! Et là, nOUs nE pOUrrOns pAs dÉtEctEr lA phrAsE cAr EllE nE fInIt pAs pAr Un pOInt

Pour information, la méthode des strings upper() de la ligne 8 renvoie un string qui est la transformation en majuscule du string sur lequel on agit :

>>> "a".upper() 'A' >>> "Alors, ça donne quoi ?".upper() 'ALORS, ÇA DONNE QUOI ?'

...CORRECTION...

Ligne 1 : mise en mémoire de la variable texte1.

Ligne 3 : mise en mémoire de la fonction voyelles_majuscules().

Ligne 12 : appel de la fonction voyelles_majuscules() en lui envoyant l'argument texte1.

Ligne 3 : déroulé réel de la fonction voyelles_majuscules() qui stocke l'argument texte1 dans le paramètre s.

Ligne 5 : On crée un tableau t dont chaque case est l'un des caractères du string s.

Ligne 6 : Tour à tour, pour chaque valeur d'indice i possible dans le string s.

Ligne 7 : Si la case d'indice i du tableau contient un caractère contenu dans "aeéèyuio" (est une voyelle en gros), réalise les actions situées en desous.

Ligne 8 : Elle se lit de droite à gauche : renvoie la version majuscule du caractère placé à l'indice i du tableau et place ce nouveau caractère dans la case d'indice i du tableau.

Ligne 10 : Une fois que tu as agi sur toutes les cases du tableau une par une, crée un nouveau string se basant sur les cases du tableau et renvoie ce string en tant que réponse.

Ligne 12 : On récupère la réponse de la fonction (le nouveau string) et on applique ce résultat dans la console avec la fonction native print().

3 - Boucle FOR avec lecture directe des éléments

12° Que va contenir successivement la variable de boucle c dans le programme ci-dessous ? Que va afficher le programme ?

1 2 3 4
s = "bonjour" for c in s: print(c)

...CORRECTION...

Cette fois, on ne trouve que le nom du string derrière le mot-clé in. Pas de range.

On récupère donc directement les caractères et pas les indices possibles.

On récupère donc d'abord "b", puis "o" au tour de boucle suivant, puis "n"... jusqu'à "r".

13° Compléter la fonction nb_de_questions_v2() pour qu'elle parvienne à renvoyer le nombre de questions dans le string fourni. Il suffit donc de compter le nombre de points d'interrogation. Attention, on vous demande d'utiliser impérativement une lecture caractère par caractère à l'aide d'une boucle for c in s, et pas une boucle récupérant les indices des caractères.

1 2 3 4 5 6 7 8
texte1 = "Ceci est une phrase ? Ici, voici une deuxième phrase ! Et là, nous ne pourrons pas détecter la phrase car elle ne finit pas par un point" def nb_de_questions_v2(s): '''Renvoie le nombre de questions détectées dans le string s''' return 0 print(nb_de_questions_v2(texte1))

...CORRECTION...

1 2 3 4 5 6 7 8 9 10 11 12 13
texte1 = "Ceci est une phrase ? Ici, voici une deuxième phrase ! Et là, nous ne pourrons pas détecter la phrase car elle ne finit pas par un point" def nb_de_questions(s): '''Renvoie le nombre de questions détectées dans le string s''' nb = 0 for c in s: if c == '?': nb = nb + 1 return nb print(nb_de_questions(texte1))

Activité publiée le 13 03 2022
Dernière modification : 13 03 2022
Auteur : ows. h.