python index string

Identification

Infoforall

17 - Index et strings


Nous allons voir aujourd'hui un plus en détails les strings.

Il s'agit de variables qui font référence à des caractères contenus dans la chaine de... caractères. On peut donc lire le string un caractère à la fois.

Logiciel nécessaire pour l'activité : Thonny ou juste Python 3

Evaluation ✎ : questions 05

1 - Strings

Commençons par le premier type possédant un index que vous ayez rencontré : le string.

1 - Déclaration d'un string avec des guillemets en Python

Les éléments délimitateurs sont les guillemets.

On peut utiliser les guillemets simples ou doubles mais Python utilise les simples lors des affichages de "contenu".

Exemple

>>> a = "5" >>> a*2 '55' >>> type(a) <class 'str'> >>> type(a*2) <class 'str'>
2 - Nombre d'éléments stockés avec len

On peut utiliser la fonction native len pour obtenir le nombre d'éléments (ici des caractères) stockés dans l'itérable.

Exemple

>>> a = "bonjour" >>> len(a) 7 >>> nbr = len(a) >>> nbr 7 >>> a = "bonjour !" >>> nbr = len(a) >>> nbr 9

On notera que l'espace est bien un caractère : il peut s'agir de l'espace, le code ASCII 32 qui contient donc " ".

01° Réaliser un programme qui affiche (sans stockage) dans la console le nombre de caractères (caractères d'espacement et de ponctuation inclus) de chacune des phrases suivantes :

Phrase 1

On notera que l'index du premier élément ne porte pas le numéro 1 mais bien le numéro 0 !

Phrase 2

On notera également qu'on peut avoir accès à l'élément 5 sans avoir lu au préalable le 2,3 et 4. Ce n'est pas le cas pour toutes les structures de données.

Réaliser ensuite un programme qui stocke (sans les afficher) les valeurs dans des variables qu'on notera a

...CORRECTION...

1er programme (qui affiche)

1 2 3 4 5
phrase1 = "On notera que l'index du premier élément ne porte pas le numéro 1 mais bien le numéro 0 !" phrase2 = "On notera également qu'on peut avoir accès à l'élément 5 sans avoir lu au préalable le 2,3 et 4. Ce n'est pas le cas pour toutes les structures de données." print(len(phrase1)) print(len(phrase2))

On obtient alors les réponses suivantes à l'écran (à destination d'un humain): 89 et 155.

2e programme (qui mémorise)

1 2 3 4 5
phrase1 = "On notera que l'index du premier élément ne porte pas le numéro 1 mais bien le numéro 0 !" phrase2 = "On notera également qu'on peut avoir accès à l'élément 5 sans avoir lu au préalable le 2,3 et 4. Ce n'est pas le cas pour toutes les structures de données." a = len(phrase1) b = len(phrase2)
3 - Accès à l'un des éléments avec [index]

Pour accéder à l'un des caractères en particuliers, on peut noter le nom de la variable suivi de crochets et y placer l'index du numéro voulu.

Exemple

>>> a = "bonjour" >>> a[0] 'b' >>> b[1] 'o' >>> lettre = a[0] >>> lettre 'b' >>> lettre = a[1] >>> lettre 'o' >>> lettre = a[5] >>> lettre 'u'

La correspondance index - caractère donne ceci sur l'exemple

Index 0 1 2 3 4 5 6
'bonjour' 'b' 'o' 'n' 'j' 'o' 'u' 'r'

On notera que l'index du premier élément porte le numéro d'index 0 et pas le numéro 1 !

02° Trouver le 27e caractére de chacune des phrases suivantes :

Phrase 1

On notera que l'index du premier élément ne porte pas le numéro 1 mais bien le numéro 0 !

Phrase 2

On notera également qu'on peut avoir accès à l'élément 5 sans avoir lu au préalable le 2,3 et 4. Ce n'est pas le cas pour toutes les structures de données.

Vous réaliserez un programme qui les affiche dans la console uniquement. Pas de mémorisation.

...CORRECTION...

1 2 3 4 5
phrase1 = "On notera que l'index du premier élément ne porte pas le numéro 1 mais bien le numéro 0 !" phrase2 = "On notera également qu'on peut avoir accès à l'élément 5 sans avoir lu au préalable le 2,3 et 4. Ce n'est pas le cas pour toutes les structures de données." print(phrase1[26]) print(phrase2[26])
4 - Lecture des éléments un à un par index (méthode classique par boucle numérique)

On peut lire les caractères du string un par un en utilisant une boucle FOR couplée à la fonction len pour connaitre la valeur limite à donner à la variable de boucle.

Ainsi avec "bonjour", on a 7 lettres avec un index 0-1-2-3-4-5-6.

Il faudrait donc utiliser for index in range(7) :

Exemple

1 2 3 4 5
a = 'bonjour' longueur = len(a) for index in range(longueur) : print(a[index])

Point important : ici, la variable de boucle contient un nombre. On lit donc le contenu de la case à l'aide de a[index]

Ce programme va afficher ceci dans la console :

b o n j o u r

03° Réaliser d'abord un court programme qui affiche caractère par caractère l'une de deux phrases précédentes.

Ensuite, s'arranger pour que le programme compte les "e" en utilisant un compteur nbr_e. Il faudra l'initialiser avant de rentrer dans la boucle : un humain crée et place automatiquement ce compteur à 0 lorsqu'on lui demande de compter. L'ordinateur non. On rappelle que pour incrémenter, il faut utiliser . Il faudra bien entendu utiliser une instruction conditionnelle.

Phrase 1

On notera que l'index du premier élément ne porte pas le numéro 1 mais bien le numéro 0 !

Phrase 2

On notera également qu'on peut avoir accès à l'élément 5 sans avoir lu au préalable le 2,3 et 4. Ce n'est pas le cas pour toutes les structures de données.

Vous devriez découvrir 11 et 16 'e' dans les phrases 1 et 2.

...CORRECTION...

1 2 3 4 5 6 7 8 9 10 11
phrase1 = "On notera que l'index du premier élément ne porte pas le numéro 1 mais bien le numéro 0 !" longueur = len(phrase1) nbr_e = 0 for index in range(longueur) : caractere = phrase1[index] print(caractere) if caractere == 'e' : nbr_e = nbr_e + 1 print(f"Il y a eu {nbr_e} 'e' dans cette phrase.")
Finir le print par autre chose qu'un passage à la ligne

Si on désire voir les caractères s'afficher en les séparant par un tiret, on peut utiliser ceci :

1 2 3 4 5
a = 'bonjour' longueur = len(a) for index in range(longueur) : print(a[index], end="-")

On obtient alors ceci

b-o-n-j-o-u-r-
5 - Lecture des éléments un à un (méthode nominative)

Cette gestion nominative d'itérer les éléments n'existe pas dans tous les langages.

Python ou Javascript l'utilisent et cela permet parfois d'avoir un code plus lisible, au détriment de la connaissance de l'index de l'élément en train d'être traité.

1 2 3 4 5 6 7 8 9
phrase1 = "bonjour, je suis la seconde façon de faire !" nbr_e = 0 for caractere in phrase1 : print(caractere) if caractere == 'e' : nbr_e = nbr_e + 1 print(f"Il y a eu {nbr_e} 'e' dans cette phrase.")

Point important : ici, pas in range, juste le nom du string derrière le in : la variable de boucle contient directement le caractère. On lit donc le contenu simplement à l'aide de caractere

Ce programme affiche tout simplement les caractères un à un sans avoir à passer par un index dans le code :

b o n j o u r , j e s u i s l a s e c o n d e f a ç o n d e f a i r e ! Il y a eu 5 'e' dans cette phrase.

04° En utilisant la méthode du for nominatif, réaliser un programme où on déclare une chaine de caractère (contenant ce que vous voulez) et qui compte le nombre de e qu'elle contient. On stockera le résultat dans une variable nommée nbr_e.

Réaliser alors un programme qui compte (et stocke) les e, les a, les o et les i. Il affichera ensuite les résultats lettre par lettre à l'aide d'un fString.

...CORRECTION...

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
texte = "Ceci est la phrase que devra analyser votre programme" nbr_a = 0 nbr_e = 0 nbr_i = 0 nbr_o = 0 for caractere in texte : if caractere == 'e' : nbr_e = nbr_e + 1 elif caractere == 'a' : nbr_a = nbr_a + 1 elif caractere == 'i' : nbr_i = nbr_i + 1 elif caractere == 'o' : nbr_o = nbr_o + 1 print(f"Il y a eu {nbr_e} 'e', {nbr_a} 'a', {nbr_i} 'i' et {nbr_o} 'o' dans cette phrase.")

Alors, for numérique ou for nominatif ?

Ca dépend des situations.

Situation 1

Vous avez besoin de connaître le numéro d'index de l'élément que vous examinez, il faut utiliser un for "numérique" :
for index in range(len(a)) avec un accès au caractère avec a[index].
Exemple : vous ne voulez afficher qu'un caractère sur 2.

1 2 3 4 5
a = 'bonjour' longueur = len(a) for index in range(0, longueur, 2) : print(a[index])

Ce programme va afficher ceci dans la console :

b n o r

Situation 2

Si vous n'avez pas besoin de connaître le numéro d'index de l'élément que vous examinez, vous pouvez utiliser la version que vous voulez.

  • for index in range(len(a)) avec un accès au caractère avec a[index]
  • for caractere in phrase1 avec un accès au caractère avec caractere
6 - Non mutabilité des strings EN PYTHON

En Python, les strings sont non mutables (ou immuables) : cela veut dire qu'on ne peut pas modifier les lettres d'un contenu string après sa création.

>>> a = "bonjour" >>> a[0] = "d" TypeError: 'str' object does not support item assignment

D'autres langages se comportent comme Python : Java, C#, JavaScript...

Comment faire alors si on veut, mettons, changer les o minuscules en X majuscules ?

La solution : créer un nouveau string et l'affecter à une nouvelle variable qui porte le même nom que l'ancienne !

Attention : dans le code ci-dessous, le string est contenu avant et après dans une variable texte mais elle ne référence pas la même zone mémoire avant et après modification.

  • Avant modification, texte pointe vers l'identifiant-mémoire 12
  • Après modification, texte pointe vers l'identifiant-mémoire 18
String non mutable
Visualisation des modifications

VERSION avec INDEX numéroté (boucle "numérique")

1 2 3 4 5 6 7 8 9 10 11 12
texte = "bonjour" tempo = "" for index in range(len(texte)) : caractere = texte[index] if caractere == 'o' : tempo = tempo + 'X' else : tempo = tempo + caractere texte = tempo print(texte)

Voici le contenu modifié à chaque tour de boucle (lignes 4 à 9) de la variable tempo.

index contient 0, d'où : b index contient 1, d'où : bX index contient 2, d'où : bXn index contient 3, d'où : bXnj index contient 4, d'où : bXnjX index contient 5, d'où : bXnjXu index contient 6, d'où : bXnjXur

VERSION sans INDEX numéroté (boucle "nominative")

1 2 3 4 5 6 7 8 9 10 11
texte = "bonjour" tempo = "" for caractere in texte : if caractere == 'o' : tempo = tempo + 'X' else : tempo = tempo + caractere texte = tempo print(texte)

Voici le contenu modifié à chaque tour de boucle (lignes 4 à 8) de la variable tempo.

caractère contient "b", d'où : b caractère contient "o", d'où : bX caractère contient "n", d'où : bXn caractère contient "j", d'où : bXnj caractère contient "o", d'où : bXnjX caractère contient "u", d'où : bXnjXu caractère contient "r", d'où : bXnjXur

Dans d'autres langages (PHP, Ruby, C++...), le string est mutable : on peut changer directement la valeur d'un caractère.

✎ 05° Créer une fonction sans_accent qui possède un paramètre contenant un string. Elle doit renvoyer une copie de ce string en modifiant les "é", "ê" et "è" en un simple "e".

Voici son prototype :

1
def sans_accent(texte:str) -> str

Voici le code à modifier :

1 2 3
def sans_accent(texte) : '''Renvoie une copie de texte mais en remplacant les caractères accentués par une version non accentuée''' return texte

Comme on ne s'intéresse pas à la place du caractère dans le string, vous pouvez utiliser la boucle for qui vous convient le mieux.

06° Modifier les lignes 19 et 20 de la fonction etoile_mystere (voir ci-dessous) qui renvoie un string de même taille que celui reçu en paramètre. Elle devra passer les tests automatiques en renvoyant les bonnes réponses attendues. La difficulté de la question tient donc autant à la compréhension de la demande (que doit faire la fonction ?) qu'à la façon de réaliser cela (comment coder ce qu'on lui demande de faire ?).

Voici son prototype :

1
def etoile_mystere(texte:str, numero:int) -> str

La réponse sera composée presque uniquement d'étoiles ("*").

Les points ('.'), les virgules (','), les espaces (' ') ainsi que le caractère de numéro d'index fourni en argument devront être inchangés. Voir la documentation pour d'autres exemples.

>>> etoile_mystere('Bonjour à toi !', 2) '**n**** * *** *'

Le principe de la fonction est de reconstruire un nouveau string en rajoutant un par un le nouveau caractère.

Comme on doit agir en fonction du numéro d'index, nous n'avons pas le choix, il faut utiliser un FOR numérique. Sinon, cela va complexifier encore plus le code.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
def etoile_mystere(texte, numero) : '''Renvoie un string composé d'étoiles. Seuls le caractère d'index fourni, le point, la virgule et les espaces sont inchangé ::param texte(str) :: le string qui sert de base de travail ::param numero(int) :: le numéro d'index du caractère qu'on ne veut pas modifier ::return (str) :: le string composé surtout d'étoiles >>> etoile_mystere('bonjour',1) '*o*****' >>> etoile_mystere('Bonjour à tous !', 2) '**n**** * **** *' ''' tempo = "" for index in range(len(texte)) : caractere = texte[index] if caractere == '.' or caractere == ',' or caractere == ' ' : # Gestion des caractères spéciaux tempo = tempo + caractere elif index == 1000 : # condition à modifier pass # à modifier aussi else : # Tous les autres cas tempo = tempo + '*' return tempo if __name__ == '__main__' : import doctest doctest.testmod() chaine = 'Bonjour à tous !' chaine = etoile_mystere(chaine,2) print(chaine)

Exemple si on utilise etoile_mystere("Bonjour à tous !",2)

  • Initialement, tempo = ""
  • Avec caractere = texte[0] = "B", on construit tempo = "*"
  • Avec caractere = texte[1] = "o", on construit tempo = "**"
  • Avec caractere = texte[2] = "n", on construit tempo = "**n"
  • Avec caractere = texte[3] = "j", on construit tempo = "**n*"
  • ...

Ligne 17 - Utilisation du or : Vous pouvez voir l'utilisation d'un OU (OR) qui permet de valider à True le test si l'une des conditions est vraie.

if caractere == '.' or caractere == ',' or caractere == ' ' : # Gestion des caractères spéciaux tempo = tempo + caractere

Cela permet d'alléger l'écriture en évitant la multitude de elif à la suite.

if caractere == '.' : # Gestion des caractères spéciaux tempo = tempo + caractere elif caractere == ',' : # Gestion des caractères spéciaux tempo = tempo + caractere elif caractere == ' ' : # Gestion des caractères spéciaux tempo = tempo + caractere

...CORRECTION...

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
def etoile_mystere(texte, numero) : '''Renvoie un string composé d'étoiles. Seuls le caractère d'index fourni, le point, la virgule et les espaces sont inchangé ::param texte(str) :: le string qui sert de base de travail ::param numero(int) :: le numéro d'index du caractère qu'on ne veut pas modifier ::return (str) :: le string composé surtout d'étoiles >>> etoile_mystere('bonjour',1) '*o*****' >>> etoile_mystere('Bonjour à tous !', 2) '**n**** * **** *' ''' tempo = "" for index in range(len(texte)) : caractere = texte[index] if caractere == '.' or caractere == ',' or caractere == ' ' : # Gestion des caractères spéciaux tempo = tempo + caractere elif index == numero : # Gestion du cas numéro d'index voulu tempo = tempo + caractere else : # Tous les autres cas tempo = tempo + '*' return tempo if __name__ == '__main__' : import doctest doctest.testmod() chaine = 'Bonjour à tous !' chaine = etoile_mystere(chaine,2) print(chaine)

2 - FAQ

Rien pour l'instant

Des informations supplémentaires dans la partie FICHES

La prochaine fois, nous allons voir d'autres types de structures de données dans lesquelles placer d'autres choses que des caractères.

Activité publiée le 22 11 2020
Dernière modification : 22 11 2020
Auteur : ows. h.