[Python 3] Extraire chaque mot d’une chaine de caractères

Ce second article consacré au langage Python s’adresse aux lecteurs ayant déjà quelques notions de base du langage; je m’efforcerai, néanmoins, de simplifier et d’expliquer au maximum chaque ligne de code. Pour ceux qui ne souhaitent pas s’embarrasser des explications, le script final se trouve à la fin de l’article.

Nous allons voir, ici, comment manipuler les « strings » (chaines de caractères – cdc) afin d’extraire chaque « mot » ( chaque groupe de caractères que nous appellerons ainsi par commodité) d’une cdc et l’enregistrer dans une « liste » (variable pouvant contenir plusieurs valeurs).

Prenons une cdc quelconque constituée de mots et enregistrons la dans une variable que nous appellerons cdc :

cdc = "A8zx 7r:t i 23.54 <i1 q+2N"

C’est autour des espaces que nous allons articuler notre travail puisque, ce sont finalement, eux qui définissent nos mots.

Commençons donc par compter le nombre d’espaces dans notre cdc :

esp = cdc.count(" ")

Que nous dit cette ligne ?
Dans notre variable cdc, autrement dit dans notre chaine : A8zx 7r:t i 23.54 , compte (.count) le nombre d’espaces (« ») et enregistre ce nombre dans la variable esp

Voyons ce que nous obtenons :

cdc = "A8zx 7r:t i 23.54 <i1 q+2N"
esp = cdc.count(" ")
print(esp)

Résultat : 5

Nous avons, effectivement 5 espaces dans notre cdc.
Il va maintenant s’agir de déterminer le début et la fin de chaque mot…
Nous allons le faire en identifiant les index (l’index correspond, ici, au numéro de chaque caractère dans notre cdc, le premier caractère de notre chaine ayant 0 pour index; le second, 1; le troisième, 2 etc..) de la première lettre de notre mot et de l’espace qui le termine.

Puisque, pour chaque mot, nos index vont changer, nous allons donc utiliser des variables pour identifier, pour chaque mot, l’index du début et celui de fin.
Soit deb l’index de début et fin l’index de fin.
L’index du premier caractère du premier mot de notre cdc correspond au premier caractère de notre cdc, il prend donc la valeur 0 :

deb = 0

Pour déterminer l’index du premier espace, nous utilisons un code très proche de celui que nous avons écrit pour compter le nombre d’espaces dans notre cdc :

fin = cdc.index(" ")

Nous avons remplacé la fonction count() par la fonction index(), qui détermine l’index de la première occurrence de la chaine se trouvant entre ses parenthèses, autrement dit, dans notre cas, l’espace.
Faisons un petit test :

cdc = "A8zx 7r:t i 23.54 <i1 q+2N"
fin = cdc.index(" ")
print(fin)

4

Le premier espace de notre cdc a 4 pour numéro d’index et se trouve en 5e position.

Il nous faut maintenant créer notre « liste », cette variable particulière qui va accueillir chaque mot de notre cdc. Il nous suffit de nommer notre variable, appelons la maListe par exemple, et de la faire suivre de = []; Python sait ainsi qu’il sagit d’une liste, vide pour l’instant.

maListe = []

Récapitulons : notre premier mot commence avec l’index 0 enregistré dans la variable deb et se termine par l’index 4 de notre premier espace, enregistré dans la variable fin.
Faisons un essai en extrayant le premier mot de notre chaine contenue dans la variable cdc.
Pour faire l’extraction, il suffit de faire suivre la notre cdc de [index du début:index de fin] soit :
A8zx 7r:t i 23.54 [0:4]

Contrôlons :

print("A8zx 7r:t i 23.54 <i1 q+2N"[0:4])

A8zx

Rendons notre code plus lisible et plus adapté à notre projet en remplaçant toutes nos valeurs absolues par des variables :

cdc[deb:fin]

Et puisque nous voulons enregistrer chaque mot dans notre liste pour, éventuellement, pouvoir le rappeler par la suite, nous allons modifier le code comme ceci :

maListe.append(cdc[deb:fin])

Ici, la fonction append() permet d’enregistrer un nouvel élément (l’extraction de notre mot, contenu dans entre les parenthèses) à notre liste maListe.
Bon, voilà pour le principe… maintenant, puisque nous avons plusieurs mots, il va falloir répéter ce principe autant de fois qu’on a de mots par l’intermédiaire d’une boucle.
Tout d’abord, nous allons déterminer le nombre de fois que l’on va répéter l’opération.
Dans notre cas de figure, nous avons 6 mots séparés par 5 espaces… En règle générale, nous aurons un mot de plus que d’espaces, on peut donc dire que notre nombre de mots est égal à notre variable esp + 1. Ecrivons donc notre boucle :

for i in range(0, esp + 1):

Qu’est ce que cela signifie ? traduisons mot à mot…

for : pour
i : i est notre compteur qui s’incrémente à chaque tour de la boucle
in : dans
range : champ
(0, esp + 1) : 0, 6
les 2 points : terminent la ligne et annoncent l(es)’instruction(s) à répéter.

Autrement dit, pour chaque valeur de i (i = 0, i = 1, i = 2…. i = 5; i est bien répété 6 fois entre sa valeur 0 et sa valeur 5 !!!), accomplir la tache d’extraction du mot et l’enregistrer dans la liste maListe.

Affichons les élements de notre liste maListe, à l’aide de la fonction print(),et voyons à quoi ressemble son contenu maintenant :

cdc = "A8zx 7r:t i 23.54 <i1 q+2N"

esp = cdc.count(" ")
deb = 0
fin = cdc.index(" ")
maListe = []

for i in range(0, esp + 1):
    maListe.append(cdc[deb:fin])
    print(maListe)

Avant de commenter le résultat, retenons qu’en langage Python, l’intentation (tabulation) a une importance capitale qui contribue à la lisibilité du code : toutes les actions qui doivent être répétées dans la boucle sont écrites en retrait d’une tabulation par rapport à la ligne qui initie notre boucle.

A8zx
A8zx A8zx
A8zx A8zx A8zx
A8zx A8zx A8zx A8zx
A8zx A8zx A8zx A8zx A8zx
A8zx A8zx A8zx A8zx A8zx A8zx

Bon, ce n’est pas encore le résultat espéré mais c’est plutôt encourageant : nous avons 6 lignes qui correspondent aux 6 répétitions de notre boucle, autrement dit, aux 6 mots contenus dans notre cdc; et à chaque nouvelle boucle, nous avons un mot qui s’ajoute aux précédents. Notre boucle fonctionne donc correctement, il va maintenant falloir lui faire extraire chaque mot de la cdc, et non pas répéter le premier mot uniquement.

Comment extraire le second mot ? Pourquoi ne pas amputer notre variable cdc du premier mot et recommencer notre routine ? Remplaçons notre variable cdc par sa nouvelle valeur :

cdc = cdc[fin+1:]

fin+1 (soit l’index 5 à ce niveau de l’opération) correspond à l’index du caractère qui suit notre premier espace (rappelons que la variable fin enregistre l’index de l’espace) donc il s’agit du caractère 7 de notre cdc.
La suite du code entre les crochets ne contient que :, autrement dit, puisqu’on ne spécifie pas l’index de fin, Python enregistre le reste de la cdc jusqu’au dernier caractère.
Contrôlons notre ligne de code :

cdc = "A8zx 7r:t i 23.54 <i1 q+2N"

esp = cdc.count(" ")
deb = 0
fin = cdc.index(" ")
maListe = []

for i in range(0, esp + 1):
    maListe.append(cdc[deb:fin])
    cdc=cdc[fin+1:]
    print(cdc)

7r:t i 23.54 i 23.54 54 1 q+2N
i 23.54
54
1 q+2N
N

Notre premier mot a disparu de notre variable cdc, c’est ce que nous voulions !
Le second mot de la cdc originelle est maintenant devenu le premier.
La boucle ne calcule plus que 5 lignes, ce qui est conforme à nos attentes… les autres lignes sont amputées, à chaque fois, par notre instruction cdc=cdc[fin+1:], qui modifie notre variable cdc.
Tout est normal.
Afin d’extraire notre nouveau « premier » mot, il va falloir recalculer sa variable fin; il s’agit juste de répéter la ligne fin = cdc.index(« »), dans notre boucle… afin que le calcul se refasse automatiquement pour chaque nouveau mot.
Testons :

cdc = "A8zx 7r:t i 23.54 <i1 q+2N"

esp = cdc.count(" ")
deb = 0
fin = cdc.index(" ")
maListe = []

for i in range(0, esp + 1):
    maListe.append(cdc[deb:fin])
    cdc=cdc[fin+1:]
    fin = cdc.index(" ")
    print(cdc)

ERREUR !!!

L’erreur était prévisible, à un moment donné, puisque notre dernier mot n’est pas suivi d’espace.
Python affiche donc un message d’erreur. Comment contourner le problème ? Avec une simple astuce : nous allons vérifier, à chaque fois que notre variable cdc est amputée d’un mot, qu’elle contient toujours au moins un espace et c’est notre fonction cdc.count(« ») qui va nous aider. Nous allons instruire Python au travers d’une « condition »; ajoutons les lignes suivantes à notre code :

    if cdc.count(" ")!=0:
        fin = cdc.index(" ")
    else:
        fin = len(cdc)

Vous noterez, tout d’abord, qu’encore une fois, nous indentons notre code selon le même principe que précédemment, avec notre boucle.
if : si
cdc.count(« ») : nombre d’espaces dans la variable cdc
!= : signifie littéralement différent, autrement dit, si le nombre d’espaces dans la variable cdc est différent de 0, donc tant qu’il y a des espaces, on recalcule la variable fin.
else: : sinon (s’il n’y a plus d’espace)
len(cdc) : len est l’abréaviation de length en anglais, autrement dit, la longueur. Ici, on entend le nombre total de caractères (restant à) de notre variable cdc. Cette information jouera le rôle d’index et définira le dernier caractère de notre dernier mot.

Revoyons la globalité de notre code en respectant l’indentation :

cdc = "A8zx 7r:t i 23.54 <i1 q+2N"

esp = cdc.count(" ")
deb = 0
fin = cdc.index(" ")
maListe = []

for i in range(0, esp + 1):
    maListe.append(cdc[deb:fin])
    cdc=cdc[fin+1:]
    if cdc.count(" ")!=0:
        fin = cdc.index(" ")
    else:
        fin = len(cdc)

et faisons un contrôle, cette fois ci, en bonne et due forme.
Nous allons contrôler toutes les valeurs enregistrées par notre variable maListe.
On appelle chacune d’entre elles par leur numéro d’index.
Dans ce cas précis, l’index ne sera plus la position du caractère dans la cdc mais la position de chaque mot dans la variable maListe.

for j in range(len(maListe)):
    print(maListe[j])

La première ligne incrémente la valeur j de 0 (sous entendu puisque non précisé) à len(maListe), c’est à dire ici le nombre d’éléments contenus dans maListe.
Autrement dit, pour chaque valeur contenue dans maListe à partir de 0, incrémente, à chaque fois j de 1 (
première valeur contenue dans maListe – A8zx – j = 0
deuxième valeur contenue dans maListe – 7r:t – j = 1
etc… ).
la seconde affiche l’élément de maListe dont l’index vaut j
Voici notre code :

cdc = "A8zx 7r:t i 23.54 <i1 q+2N"

esp = cdc.count(" ")
deb = 0
fin = cdc.index(" ")
maListe = []

for i in range(0, esp + 1):
    maListe.append(cdc[deb:fin])
    cdc=cdc[fin+1:]
    if cdc.count(" ")!=0:
        fin = cdc.index(" ")
    else:
        fin = len(cdc)

for j in range(len(maListe)):
    print(maListe[j])

A8zx
7r:t
i
23.54
<i1
q+2N

Tout semble marcher parfaitement, sauf que…
si nous changeons la valeur de notre variable cdc et lui attribuons une cdc sans espace

cdc = "q+2N"

notre programme va planter ! Puisque le programme ne trouve pas d’espace dans la cdc…
Pour cela nous allons légèrement modifier le début de notre script et notre variable fin en copiant-collant les lignes suivantes :

if cdc.count(" ")!=0:
    fin = cdc.index(" ")
else:
    fin = len(cdc)

à la place de :

fin = len(cdc)

voici, à présent, notre code qui fonctionne, quel que soit l’état de notre variable cdc:

maChaine = cdc = "A8zx 7r:t i 23.54 <i1 q+2N"

esp = cdc.count(" ")
deb = 0
if cdc.count(" ")!=0:
    fin = cdc.index(" ")
else:
    fin = len(cdc)
maListe = []

for i in range(0, esp + 1):
    maListe.append(cdc[deb:fin])
    cdc=cdc[fin+1:]
    if cdc.count(" ")!=0:
        fin = cdc.index(" ")
    else:
        fin = len(cdc)

for j in range(len(maListe)):
    print(maListe[j])

Avez vous remarqué que j’ai légèrement modifié la ligne de code contenant ma cdc ?

maChaine = cdc = "A8zx 7r:t i 23.54 <i1 q+2N"

A force d’amputer la variable cdc pour extraire chacun des mots, il ne reste plus de caractère dans ma variable cdc à la fin de mon opération.
En ajoutant maChaine, je conserve ainsi une copie exacte de la chaine initiale.

Nous avons maintenant un code qui marche mais qui ne plaira pas aux puristes :
notre condition

    if cdc.count(" ")!=0:
        fin = cdc.index(" ")
    else:
        fin = len(cdc)

est répétée 2 fois ! même si un simple copier-coller fait l’affaire, le code est lourd… le but du est de le rendre le plus lisible (plus simple ?!) possible… Pour cela, nous allons faire appel à une « fonction ». Le principe d’une fonction est le suivant : on lui envoie des données (ou pas), elle les traite et renvoie un résultat. Ici, nous allons envoyer la variable cdc pour que notre fonction vérifie si elle contient des espaces ou non.
Nous allons rédiger notre fonction en tout début de script.
Chaque fonction commence par la commande def, suivie du nom de la fonction suivie de parenthèses et de :
Nous appellerons notre fonction controle

def controle(zz):

Ici, nous avons inséré une variable, zz, entre les parenthèses de notre fonction afin de lui signifier que nous allons lui envoyer des informations lorsque nous l’appellerons, en l’occurrence, la variable cdc.

def controle(zz):

    if zz.count(" ")!=0:
        return zz.index(" ")
    else:
        return len(zz)

Encore une fois, l’indentation est extrêment importante, ici aussi; l’occulter conduira fatalement à une erreur de traitement.
Cette fonction ressemble sensiblement au code que nous utilisions auparavant pour déterminer la valeur de notre variable fin, à la différence que la variable cdc devient zz et que l’on intègre la commande return à la place de notre variable fin.
La variable cdc est donc remplacée par zz qui représente, dans notre fonction, la valeur qui sera traitée par la fonction.
La commande return se charge ensuite de renvoyer à la variable fin de notre programme principal, le résultat de son traitement.

Il ne nous reste plus qu’à appeler notre fonction depuis notre programme principal en remplaçant, à chaque fois, cettte condition

if cdc.count(" ")!=0:
    fin = cdc.index(" ")
else:
    fin = len(cdc)

par

fin = controle(cdc)

Nous appelons la fonction par son nom. Entre parenthèses, nous lui adressons la variable qui doit être traitée; ensuite la commande return renvoie le résultat du traitement de notre fonction qui est enregistré dans la variable fin.

Voici le code final de notre projet :

def controle(zz):

    if zz.count(" ")!=0:
        return zz.index(" ")
    else:
        return len(zz)

maChaine = cdc = "A8zx 7r:t i 23.54 <i1 q+2N"

esp = cdc.count(" ")
deb = 0
fin = controle(cdc)
maListe = []

for i in range(0, esp + 1):
    maListe.append(cdc[deb:fin])
    cdc=cdc[fin+1:]

    fin = controle(cdc)

for j in range(len(maListe)):
    print(maListe[j])

A8zx
7r:t
i
23.54
<i1
q+2N

Voilà petit exercice qui nous a permis d’aborder certaines des techniques de base en programmation : variables, boucles, conditions, fonctions… gardons, néanmoins, en mémoire que l’on peut souvent améliorer un script comme c’est le cas ici !

Voici un autre script qui donne exactement le même résultat, en utilisant, la fonction split() qui sépare le contenu d’une cdc…

cdc = "A8zx 7r:t i 23.54 <i1 q+2N"
maListe = cdc.split(" ") # la fonction split sépare et enregistre chaque mot de notre cdc dans la liste maListe 

for i in maListe # boucle d'affichage du contenu de la liste maListe
    print(i)

A8zx
7r:t
i
23.54
<i1
q+2N

Voici une autre méthode qui utilise le principe des « listes en intention » pour l’affichage, que je n’aborderai pas ici, et qui présente le même résultat en rendant ce code encore plus minimaliste :

maListe = "A8zx 7r:t i 23.54 <i1 q+2N".split(" ")
[print(i) for i in maListe]

On pourrait encore réduire cet algorithme jusqu’à le faire tenir sur une simple ligne :

[print(i) for i in "A8zx 7r:t i 23.54 <i1 q+2N".split(" ")]

je ne recommande, cependant, pas de contracter un code à l’extrême, car il devient plus difficile à lire et à maintenir par la suite.

Pour terminer, je vous soumets l’écriture, qui selon moi, est la mieux optimisée puique :

  •  nous conservons notre chaine dans sa globalité dans la variable cdc.
  • nous enregistrons efficacement chaque mot dans notre liste maListe en une seule ligne de code.
  • nous affichons le résultat de notre opération d’extraction avec une écriture qui tient sur une seule ligne également.
cdc = "A8zx 7r:t i 23.54 <i1 q+2N"
maListe = cdc.split(" ")
[print(i) for i in maListe]
Publicités

2 réflexions sur “[Python 3] Extraire chaque mot d’une chaine de caractères

  1. Hello!
    Je viens de découvrir ton blog en cherchant une info sur VBA, mais je code aussi en Python.
    Je trouve que ton article représente bien un des aspects de Python: il existe de nombreuses fonctions déjà optimisées notamment en ce qui concerne la manipulation de chaines. Inutile donc de réinventer la roue à chaque fois! Cependant avant de les utiliser il faut bien comprendre leur fonctionnement et c’est pourquoi il peut être utile de les disséquer au moins une fois.

    A bientôt

    • Bonjour Will,

      je trouvais intéressant de rédiger cet article car il aborde le thème de l’extraction des caractères d’une chaîne, auquel est confronté n’importe quel développeur qui débute, et permet de faire un tour rapide de quelques notions de base en programmation telles ques les variables, boucles, conditions, fonctions etc… Cet exemple démontre surtout qu’on peut aborder un même problème sous différents angles et je te rejoins parfaitement concernant la nécessité de comprendre les techniques mises à notre disposition par un langage.

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s