Aller au contenu

Parcourir

Il faut connaître les différentes façons de parcourir un objet chaîne:

  • for ... in ...
  • for ... in enumerate(...)
  • for ... in range(....)

Parcourir les caractères

On peut parcourir les caractères d'une chaîne avec for in:

>>> a = "Je suis une chaîne"
>>> for caractere in a:
...     print(caractere)
... 
J
e

s
u
i
s

u
n
e

c
h
a
î
n
e

Parcourir avec indice et caractère

>>> a = "Je suis une chaîne"
>>> for i, c in enumerate(a):
...     print(i, c)
... 
0 J
1 e
2  
3 s
4 u
5 i
6 s
7  
8 u
9 n
10 e
11  
12 c
13 h
14 a
15 î
16 n
17 e

Parcourir avec les indices

>>> a = "Je suis une chaîne."
>>> for indice in range(len(a)):
...     print(indice, a[indice])
... 
0 J
1 e
2  
3 s
4 u
5 i
6 s
7  
8 u
9 n
10 e
11  
12 c
13 h
14 a
15 î
16 n
17 e
18 .

Exercice 1

Écrire un code possible pour le corps de la fonction suivante:

def compte_e(chaine):
    """
    chaine -- chaine de caractères

    renvoie le nombre de lettres e, E de la chaîne
    """

le principe

Le principe à utiliser ici est encore celui de l'accumulateur déjà utilisé.

On utilise une variable compteur et on "visite" un par un les caractères de la chaîne.

On "accumule" des 1 dans compteur à chaque visite d'un caractère e ou E, ainsi au final compteur = 1 + 1 + 1 + ... + 1, expression comptant autant de 1 qu'il y a de caractères e ou E dans la chaîne.

Après chaque "visite" de caractère, compteur aura pour valeur le nombre de caractères 'e' ou 'E' déjà visités (pour cela, avant toute visite, on doit bien sûr intialisé le compteur à 0).

En fin de visite des caractères, tous les caractères de la chaîne ayant été visités, la variable compteur contiendra le nombre total d'occurrences des lettres de l'ensemble {'e'; 'E'}.

Pseudo-code
compteur ← 0
Pour chaque caractère de chaine:
    si le caractère est un e ou un E:
        on ajoute 1 au compteur    
Un code python possible
def compte_e(chaine):
    """
    chaine -- chaine de caractères

    renvoie le nombre de lettres e de la chaîne
    """
    compteur = 0
    for caractere in chaine:
        if caractere == 'e' or caractere == 'E': compteur += 1
    return compteur

On peut vouloir mettre en évidence le fait qu'on ne fait rien si le caractère lu n'est pas 'e' ou 'E' (certains trouveront le code plus facile à lire ainsi, cela dépend de chacun, à vous de voir):

def compte_e(chaine):
    """
    chaine -- chaine de caractères

    renvoie le nombre de lettres e de la chaîne
    """
    compteur = 0
    for caractere in chaine:
        if caractere == 'e' or caractere == 'E': 
            compteur += 1
        else:
            pass # instruction "on ne fait rien!"
    return compteur
Pour compter aussi é, è, ...

On pourrait aussi vouloir compter é, è, ê dans les lettres e. On peut alors utiliser in (plutôt que d'accumuler les or):
fichier ipynb

Note

On rappelle que l'extension .ipynb est celle des fichiers jupyter notebook.

Une version statique html de ce fichier ipynb:

déroulement

Regardons un peu en détail le déroulement sur cet essai:

def compte_e(chaine):
    """
    chaine -- chaine de caractères

    renvoie le nombre de lettres e de la chaîne
    """
    compteur = 0
    for caractere in chaine:
        if caractere == 'e' or caractere == 'E': 
            compteur += 1
        else:
            pass # instruction "on ne fait rien!"
    return compteur



a = compte_e('ether')
print(a)

On appelle la fonction (partie droite de l'affectation en ligne 17):

compte_e('ether')

On a alors la situation suivante:

On exécute la ligne:

compteur = 0

La situation:

On arrive ensuite à la ligne:

for caractere in chaine:

On teste si caractere désigne une lettre 'e' et on incrémente compteur si c'est le cas:

if caractere == 'e' or caractere == 'E': 
    compteur += 1
else:
    pass # instruction "on ne fait rien!"

On passe à la valeur suivante de caractere:

Et on exécute le if: caractere ne désigne pas un 'e', on ne fait rien. Le schéma reste le même.

On passe à la valeur suivante de caractere:

Et on exécute le if: caractere ne désigne pas un 'e', on ne fait rien. Le schéma reste le même.

On passe à la valeur suivante de caractere:

Et on exécute le if: caractere désigne un 'e', on incrémente compteur.

On passe à la valeur suivante de caractere:

Et on exécute le if: caractere ne désigne pas un 'e', on ne fait rien. Le schéma reste le même.

On termine la fonction avec la ligne return compteur et on effectue la partie gauche de l'affectation (ligne 17): on affecte ainsi l'étiquette a (de l'espace global) à l'objet contenant la valeur 2 qui a été calculée.
Rappelons qu'à ce stade, la fonction ayant terminé ses calculs, plus aucune étiquette locale à la fonction n'existe. En particulier l'objet chaîne de caractères, utilisé en argument pour l'appel, n'est plus accessible puisqu'aucune étiquette ne désigne cet objet. Mais le nombre de lettres 'e' de cette chaîne est accessible via le nom a.

La dernière étape est l'exécution de print(a) qui affiche à l'écran la valeur de l'objet désigné par a.

Exercice 2

Écrire un code possible pour le corps de la fonction suivante:

def rang_premier_e(chaine):
    """
    chaine -- chaine de caractères

    renvoie l'indice de la première lettre e trouvée dans chaine. Renvoie -1 si e n'est pas présent.
    """

Principe

On utilise une variable témoin et on "visite" un par un les caractères de la chaîne.

Au départ, on itinialise témoin à la valeur -1, pour signifier qu'avant toute visite de caractère, on n'a pas trouvé la lettre 'e'.

Après chaque "visite" de caractère, on met à jour témoin:

  • si le caractère est un 'e', la variable témoin reçoit la valeur de l'indice de la lettre visitée
  • sinon témoin reste égal à sa valeur précédente.

En fait le principe précédent n'est pas correct: il ne faut pas modifier à nouveau témoin si l'on rencontre à nouveau la lettre 'e'.
Comment savoir si le 'e' rencontré est le premier rencontré? C'est simple: si témoinne vaut plus -1, c'est qu'on a déjà rencontré un 'e', sinon c'est le premier.

On modifie donc le code d'une visite de caractère comme suit:

Après chaque "visite" de caractère, on met à jour témoin:

  • si le caractère est un 'e' et si témoin vaut -1: la variable témoin reçoit la valeur de l'indice de la lettre visitée,
  • sinon témoin reste égal à sa valeur précédente.

En fin de visite des caractères, tous les caractères de la chaîne ayant été visités, la variable témoin contiendra -1 si on n'a jamais rencontré 'e' et l'indice du premier 'e' rencontré sinon.

Pseudo-code
témoin ← -1
Pour chaque caractère de chaine:
    si le caractère est un 'e' et si témoin == -1:
        témoin ← indice du caractère
    sinon
        on ne fait rien
Un code python

Un premier code possible:

def rang_premier_e(chaine):
    """
    chaine -- chaine de caractères

    renvoie l'indice de la première lettre e trouvée dans chaine. Renvoie -1 si e n'est pas présent.
    """
    témoin = -1
    for indice, caractere in enumerate(chaine):
        if caractere == 'e' and témoin == -1: 
            témoin = indice
        else:
            pass
    return témoin
Stopper la boucle au premier e

On peut allèger ce code en profitant du fait que la fonction est stoppée dès le premier return rencontré (dès qu'on connaît l'image, on peut stopper le calcul):

def rang_premier_e(chaine):
    """
    chaine -- chaine de caractères

    renvoie l'indice de la première lettre e trouvée dans chaine. Renvoie -1 si e n'est pas présent.
    """
    for indice, caractere in enumerate(chaine):
        if caractere == 'e': return indice
    return -1

Important

La ligne return -1 n'a pas besoin de else: si dans une fonction, on rencontre un return, on sort immédiatement de la fonction puisque l'image a été obtenue.
Ainsi:

  • Soit un e dans la boucle a été rencontré et on sort de la fonction avec return indice, la ligne return -1 n'est donc jamais vue dans ce cas.
  • Soit aucun e n'est rencontré dans le parcours de la chaîne. On finit la boucle sans avoir exécuté return indice. Et dans ce cas, on exécute la ligne qui suit, c'est à dire return -1.

fichier ipynb
Et la version statique html:

Exercice 3

On appelle distance de Hamming entre deux chaînes de caractères A et B de même longueur le nombre d'indices i tels que A[i] \neq B[i].

Exemples.

  • distance('ami' , 'amu') = 1
  • distance('don' , 'bon') = 1
  • distance('zozo' , 'bobo') = 2

Écrire une fonction python prenant en entrée deux chaînes de caractères de même longueur et renvoyant la distance de Hamming entre ces deux chaînes.

Un code
def hamming(chaine, chene):
"""
chaine -- type string
chene -- type string

renvoie la distance de Hamming entre chaine et chene.
"""
assert len(chaine)==len(chene), "Attention, les deux chaînes de caractères doivent être de même longueur."

difference = 0 # compteur de différences
for k in range(len(chaine)):
    if chaine[k] != chene[k]:
        difference = difference + 1
    else:
        pass # on ne fait rien lorsque les deux caractères sont les mêmes
return difference

Tests:

>>> hamming('abri', 'ubri')
1
>>> hamming('010101', '010110')
2