Objectif : manipuler les chaînes de caractères
Niveau de difficulté : débutant
Exercice
Écrivez un script qui détermine si une chaîne contient ou non le caractère « e ».
Auteur : Gérard Swinnen
Cours : apprendre à programmer avec Python
Voir une solutionVoir une autre solutionVoir une autre solution
La solution proposée par l'auteur dans son livre
Apprendre à programmer en Python 3 est la suivante :
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
| #!/usr/bin/env python3
# coding: utf-8
# Recherche d'un caractère particulier dans une chaîne
# Chaîne fournie au départ
ch = "Monty python flying circus"
# Caractère à rechercher
cr = "e"
# Recherche proprement dite
lc = len(ch) # nombre de caractères à tester
i = 0 # indice du caractère en cours d'examen
t = False # "drapeau" à lever si le caractère recherché est présent
while i < lc: # Tant que i n'a pas atteint le bout de la chaine
if ch[i] == cr: # Si le caractère[i] de la chaine est égal au caractère à trouver
t = True # On lève le drapeau
i = i + 1 # i passe au caractère suivant
# Affichage final
print("Le caractère", cr, end = ' ')
if t: # Si le drapeau a été levé
print("est présent", end = ' ')
else:
print("est introuvable", end = ' ')
print("dans la chaîne", ch) |
On peut optimiser en sortant de la boucle
while dès que le caractère est trouvé s'il existe. Une réécriture possible est donc :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| #!/usr/bin/env python3
# coding: utf-8
# Recherche d'un caractère particulier dans une chaîne
# Chaîne fournie au départ
ch = "Monty python flying circus"
# Caractère à rechercher
cr = "e"
# Parcours de la chaîne, caractère par caractère
lc = len(ch) # nombre de caractères à tester
i = 0 # indice du caractère en cours d'examen
# On boucle sur la chaine tant que le caractère n'est pas trouvé
while i < lc and ch[i] != cr:
i+=1
# Affichage final - C'est la valeur de "i" qui détermine si le caractère est ou n'est pas présent
print("Le caractère", cr, end = ' ')
if i < lc:
print("est présent", end = ' ')
else:
print("est introuvable", end = ' ')
print("dans la chaîne", ch)) |
Python propose un opérateur nommé
in qui indique une présence dans un ensemble. Il propose aussi une expression de type
val1 if condition else val2 qui vaut "val1" si la condition est vraie et sinon "val2".
Et l'utilisation du formatage de strings permet de simplifier les affichages.
De fait, le programme peut alors s'écrire encore plus simplement :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| #!/usr/bin/env python3
# coding: utf-8
# Recherche d'un caractère particulier dans une chaîne
# Chaîne fournie au départ
ch = "Monty python flying circus"
# Caractère à rechercher
cr = "e"
print(
"Le caractère '{}' est {} dans la chaîne '{}'".format(
cr,
"présent" if cr in ch else "introuvable",
ch,
)
) |
Objectif : manipuler les chaînes de caractères
Niveau de difficulté : débutant
Exercice
Écrivez un script qui recopie une chaîne (dans une nouvelle variable), en insérant des astérisques entre les caractères.
Par exemple, « gaston » devra devenir « g*a*s*t*o*n »
Auteur : Gérard Swinnen
Cours : apprendre à programmer avec Python
Voir une solutionVoir une autre solution
La solution proposée par l'auteur dans son livre
Apprendre à programmer en Python 3 est la suivante :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| #!/usr/bin/env python3
# coding: utf-8
# Chaîne fournie au départ
ch = "Véronique"
# Caractère à insérer
cr = "*"
lc = len(ch) # nombre de caractères total
nch = ch[0] # nouvelle chaîne à construire (contient déjà le premier caractère)
# La première insertion venant après le premier caractèe, on saute celui-ci
i = 1 # indice du premier caractère à examiner (le second, en fait)
while i < lc:
# on rajoute le caractère à insérer puis le caractère lu à la nouvelle chaine
nch = nch + cr + ch[i]
i = i + 1
# Affichage
print(nch) |
Les chaines de caractères peuvent être concaténées avec l'opérateur
+.
Les chaines de caractères proposent une méthode
join dédiée à insérer un caractère entre chaque autre.
De fait, le programme tient alors en une ligne :
1 2 3 4 5 6 7
| #!/usr/bin/env python3
# coding: utf-8
# La méthode join prend tous les éléments d'un itérable (ici tous les caractères de la chaine "Véronique"),
# et les joint en une seule chaîne en utilisant le séparateur indiqué (ici '*')
# Voir la FAQ Python https://python.developpez.com/faq/?page=Liste#listtostr
print('*'.join("Véronique")) |
Objectif : manipuler les chaînes de caractères
Niveau de difficulté : débutant
Exercice
Écrivez un script qui recopie une chaîne (dans une nouvelle variable) en l'inversant. Par exemple, « zorglub » deviendra « bulgroz ».
Auteur : Gérard Swinnen
Cours : apprendre à programmer avec Python
Voir une solutionVoir une autre solutionVoir une autre solution
La solution proposée par l'auteur dans son livre
Apprendre à programmer en Python 3 est la suivante :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| #!/usr/bin/env python3
# coding: utf-8
# Inversion d'une chaîne de caractères
# Chaîne fournie au départ
ch = "zorglub"
lc = len(ch) # nombre de caractères total
i = lc - 1 # le traitement commencera à partir du dernier caractère
nch = "" # nouvelle chaîne à construire (vide au départ)
while i >= 0:
# on concatène le caractère lu à la nouvelle chaine
nch+=ch[i]
i-=1
# Affichage du résultat
print(ch, "=>", nch) |
Python propose bien d'autres outils, par exemple par découpage de la chaîne de caractères (
slicing) :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| #!/usr/bin/env python3
# coding: utf-8
# Inversion d'une chaîne de caractères
# Chaîne fournie au départ
ch = "zorglub"
lc = len(ch) # nombre de caractères de la chaine
# Par découpage de la chaîne (slicing)
# La séquence est entièrement parcourue en partant de la fin, par pas de -1
print(ch, "=>", ch[lc::-1])
# Et plus court encore (si le début ou la fin sont omis, ils sont calculés automatiquement)
print(ch, "=>", ch[::-1]) |
Ou une fonction
reversed permettant de renvoyer un itérable renversé
1 2 3 4 5 6 7 8 9 10 11 12
| #!/usr/bin/env python3
# coding: utf-8
# Inversion d'une chaîne de caractères
# Chaîne fournie au départ
ch = "zorglub"
# reversed renvoie un itérateur de la séquence inversée
# On joint les éléments de la séquence inversée pour former une chaîne de caractères,
# en utilisant un séparateur vide
print(ch, "=>", ''.join(reversed(ch))) |
Mis à jour le 17 novembre 2021 par
Sve@r
Objectif : manipuler les chaînes de caractères
Niveau de difficulté : débutant
Exercice
À partir d'une chaine quelconque (par exemple chaine="abcdefghijklmnopqrstuvwxyz" * 10), écrivez un programme qui récupère et affiche autant de caractères que possible de cette chaine sous forme de suite pyramidale.
Exemple :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| a
bc
def
ghij
klmno
pqrstu
vwxyzab
cdefghij
klmnopqrs
tuvwxyzabc
defghijklmn
opqrstuvwxyz
abcdefghijklm
nopqrstuvwxyza
bcdefghijklmnop
qrstuvwxyzabcdef
ghijklmnopqrstuvw
xyzabcdefghijklmno
pqrstuvwxyzabcdefgh
ijklmnopqrstuvwxyzab
cdefghijklmnopqrstuvw
xyzabcdefghijklmnopqrs |
Voir une solutionVoir une autre solution
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| #!/usr/bin/env python3
# coding: utf-8
chaine="abcdefghijklmnopqrstuvwxyz" * 10
# Initialisation indice de croissance
i=1
# Tant que l'indice de croissance (nb de caractères à afficher) est contenu dans les caractères restants
while i <= len(chaine):
# On affiche les "i" premiers caractères
print(chaine[:i])
# On ne garde ensuite que les caractères restants à afficher
chaine=chaine[i:]
# On incrémente l'indice de croissance
i+=1
# while |
Une autre solution plus mathématique : Cette pyramide à n caractères aura "x" lignes. Ces "x" lignes représenteront la somme des x premiers entiers naturels.
Or cette
somme des x premiers entiers est égale à (x²+x)/2. Trouver combien de lignes seront nécessaires pour afficher "n" caractères correspond à résoudre l'équation x²+x-2n=0.
Cette équation de type ax²+bx+c=0 se résout par le calcul du discriminant Δ=b²-4ac (ici Δ=1+8n). Si Δ est positif (ce qui est ici le cas puisque le nombre de lettres "n" est forcément positif), on peut trouver deux solutions, la première \[\frac{-b-\sqrt{\Delta}}{2a}\] et la seconde \[\frac{-b+\sqrt{\Delta}}{2a}\]
Dans ce cas précis, la première solution étant négative, seule la seconde est utile ici. Avec a=b=1, cela donne \[\frac{-1 + \sqrt{1+8n}}{2}\] (arrondie à l'entier immédiatement inférieur).
D'où cette autre solution :
1 2 3 4 5 6 7 8 9
| #!/usr/bin/env python3
# coding: utf-8
chaine="abcdefghijklmnopqrstuvwxyz" * 10
for i in range(1, int((-1 + (1 + 8*len(chaine))**0.5) // 2) + 1):
print(chaine[:i])
chaine=chaine[i:]
# for |
Solution pas forcément ni plus rapide ni plus simple, juste qui a le mérite d'exister (et peut-être que dans un autre contexte, pouvoir calculer dès le départ le nombre d'itérations aura un avantage)...
Mis à jour le 6 novembre 2021 par
Sve@r
Objectif : manipuler les chaînes de caractères
Niveau de difficulté : débutant
Exercice
Jules César, général et stratège romain, a été (à ce qu'il semble) le premier militaire officiel à chiffrer ses messages. Sa méthode était assez simple : il décalait les lettres de 3 rangs dans l'alphabet.
Le but de cet exercice est de créer une fonction à laquelle on donne un message et un décalage, et la fonction renvoie alors le message décalé dans l'alphabet. Il faudra faire attention que le message peut contenir des caractères ne faisant pas forcément partie de l'alphabet et dans ce cas, pour ne pas perdre la signification du texte, ces caractères doivent réapparaitre à l'identique dans le message chiffré. De plus, il faudra gérer le dépassement ('z' décalé vers la droite revient sur 'a', et 'a' décalé vers la gauche revient sur 'z').
À noter que la fonction pourra être utilisée aussi bien pour chiffrer que pour déchiffrer (il suffit pour cela de lui passer le message chiffré avec l'opposé du décalage utilisé pour retrouver le message d'origine).
Remarque: il s'agit du tout premier exercice faisant intervenir la notion de fonction à créer
Voir une solutionVoir une autre solution
Une première solution toute simple :
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
| #!/usr/bin/env python3
# coding: utf-8
# Fonction de chiffrement/déchiffrement
def cesar(msg="", clef=0):
alphabet="abcdefghijklmnopqrstuvwxyz"
chiffre=""
# On prend chaque lettre du mot (converti en minuscules)
for l in msg.lower():
# On recherche la position de la lettre dans l'alphabet
pos=alphabet.find(l)
# Si la lettre est présente
if pos != -1:
# On récupère la lettre décalée dans l'alphabet (on boucle si dépassement)
chiffre+=alphabet[(pos+clef) % len(alphabet)]
else:
# Sinon on prend la lettre originelle
chiffre+=l
# if
# for
return chiffre
# cesar()
message="Hello World !!!"
chiffre=cesar(message, 5)
dechiffre=cesar(chiffre, -5)
print(message, "=>", chiffre, "=>", dechiffre) |
Il est intéressant de noter que, conformément aux règles de l'arithmétique, le modulo fonctionne dans les deux sens (
(25+1)%26 = 0 et
(0-1)%26 = 25). Ce qui simplifie alors grandement la gestion du dépassement.
Ensuite, une fois la solution comprise, on pourra utiliser quelques raccourcis de syntaxe, par exemple remplacer un
if / else simple :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| #!/usr/bin/env python3
# coding: utf-8
# Fonction de chiffrement/déchiffrement
def cesar(msg="", clef=0):
alphabet="abcdefghijklmnopqrstuvwxyz"
chiffre=""
# On prend chaque lettre du mot (converti en minuscules)
for l in msg.lower():
# On recherche la position de la lettre dans l'alphabet
pos=alphabet.find(l)
# Gestion du chiffrement selon la présence ou pas de la lettre
chiffre+=alphabet[(pos+clef) % len(alphabet)] if pos != -1 else l
# for
return chiffre
# cesar()
message="Hello World !!!"
chiffre=cesar(message, 6)
dechiffre=cesar(chiffre, -6)
print(message, "=>", chiffre, "=>", dechiffre) |
Mis à jour le 11 novembre 2021 par
Sve@r
Objectif : manipuler les chaînes de caractères
Niveau de difficulté : intermédiaire
Exercice
L'ordinateur code tous ses caractères en binaire, suite de '1' et de '0'. Chuck Norris, qui est plus fort que l'ordinateur (rappelons qu'il peut claquer des doigts de pied et qu'il a compté deux fois jusqu'à l'infini), code ses messages en unaire, suite de '0' unique.
Dans le codage Chuck Norris, le '0' est codé '00' et le '1' est codé '0'. Puis un espace, puis ensuite autant de '0' que le message contient de '0' ou '1' successifs. Par exemple la suite "10000111" sera traduite de la façon suivante :
- "0" pour le premier "1" puis "0" parce que la suite ne contient qu'un chiffre "1" ;
- "00" parce que là la suite est constituée de "0" puis "0000" parce qu'il y a quatre "0" successifs ;
- "0" pour la suite de "1", puis "000" parce qu'il y a trois "1" successifs.
Ce qui donnera "0 0 00 0000 0 000".
Le but de l'exercice est d'écrire une fonction qui code un message binaire (ex. '10000111') en unaire (ici '0 0 00 0000 0 000') puis une autre fonction qui décode un message unaire en binaire.
Voir une solutionVoir une autre solutionVoir une autre solution
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 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
| #!/usr/bin/env python3
# coding: utf-8
# Codage Chuck Norris (binaire vers unaire)
def binaire2unaire(binaire, table):
# On prépare le résultat unaire
unaire=""
# Mémorisation du caractère précédent pour détecter le changement
prev=""
# Il faut un compteur de répétitions
rep=0 # Facultatif car la première occurrence le crée. Mais pour la forme...
# Traitement de tous les caractères du binaire
# Comme il faudra faire un traitement après le dernier caractère
# On lui rajoute "artificiellement" une valeur pour gérer le dernier caractère utile
for b in binaire + ".":
# Si le caractère a changé
if b != prev:
# Si on n'est pas sur le premier cas (déjà un caractère mémorisé)
if prev:
# On complète le unaire
unaire+=" %s %s" % (table[prev], "0" * rep)
# Le compteur de répétitions est remis à 0 (création à la première itération si pas créé avant la boucle)
rep=0
# On mémorise ce nouveau caractère
prev=b
# if
# Cas général, quel que soit le caractère on incrémente la répétition
rep+=1
# for
# Travail terminé (mais la chaine commence par un espace inutile)
return unaire[1:]
# binaire2unaire()
# Décodage Chuck Norris (unaire vers binaire)
def unaire2binaire(unaire, table):
# On crée la table de décodage en inversant clefs et valeurs de la table de codage
decode=dict()
for (k, v) in table.items(): decode[v]=k
# On prépare le résultat binaire
binaire=""
# On commence par découper le unaire sur l'espace
mesg=unaire.split(" ")
# On récupère le message découpé de 2 en 2
for i in range(0, len(mesg), 2):
# Le premier élément est le code, le second le nombre de répétitions
binaire+=decode[mesg[i]] * len(mesg[i+1])
# Travail terminé
return binaire
# unaire2binaire()
# Test
# La table de traduction binaire/unaire
table={
"1" : "0",
"0" : "00",
}
# Le message de base
mesg="10000111"
# Le codage
unaire=binaire2unaire(mesg, table)
# Le décodage
binaire=unaire2binaire(unaire, table)
# Résultat
print("message originel: [{}]".format(mesg))
print("codage: [{}]".format(unaire))
print("décodage: [{}]".format(binaire))
print("vérification: {}".format("ok" if binaire == mesg else "bad")) |
Généralement, tout algorithme de la forme...
1 2 3
| resultat=initialisation
for x in iteration:
if verification_eventuelle(x): resultat=resultat + action(x) |
... peut être remplacé par une liste en compréhension (appelée aussi "liste en intension") qui est alors de la forme
resultat=[action(x) for x in iteration if verification_eventuelle(x)]. Le terme "liste" doit être pris au sens large englobant tous les ensembles Python (tuples, listes, ensembles, dictionnaires).
Pour la fonction de conversion vers l'unaire, cela ne s'applique pas (algorithme trop complexe). Mais la fonction de conversion vers le binaire, elle, correspond parfaitement à ce schéma. Déjà pour créer la table de décodage et aussi dans la boucle finale de création du message binaire.
Ainsi cette fonction peut se réécrire de cette manière :
1 2 3 4 5 6 7 8 9 10 11
| # Décodage Chuck Norris (unaire vers binaire)
def unaire2binaire(unaire, table):
# On crée la table de décodage au travers d'un dictionnaire en compréhension
table=dict((v, k) for (k, v) in table.items())
# On commence par découper le unaire sur l'espace
mesg=unaire.split(" ")
# On crée directement le résultat au travers d'une liste en compréhension
return "".join(table[mesg[i]] * len(mesg[i+1]) for i in range(0, len(mesg), 2))
# unaire2binaire() |
Maintenant, le module "itertools" possède différents outils permettant de manipuler les itérables. Un de ces outils est la fonction
groupby qui permet de grouper l'itérable par le nombre de caractères identiques. Ce qui semble parfait pour la fonction de conversion du binaire vers l'unaire.
Ainsi cette fonction peut se réécrire de cette manière :
1 2 3 4 5 6 7 8 9 10 11 12 13
| # Codage Chuck Norris (binaire vers unaire)
from itertools import groupby
def binaire2unaire(binaire, table):
# On prépare le résultat unaire
unaire=""
# On traite le message binaire dans lequel les suites de caractères identiques ont été regroupées
for (k, g) in groupby(binaire):
unaire+=" %s" % " ".join((table[k], "0" * len(tuple(g))))
# Travail terminé (mais la chaine commence par un espace inutile)
return unaire[1:]
# binaire2unaire() |
Et comme vu précédemment, tout algorithme de création simple d'itérable peut alors être transformé en liste en compréhension.
Ce qui peut alors permettre d'en arriver à cette solution un peu ardue mais qui montre pleinement les possibilités de Python...
1 2 3 4 5 6 7 8 9
| # Codage Chuck Norris (binaire vers unaire)
from itertools import groupby
def binaire2unaire(binaire, table):
# On crée une liste en compréhension sur le groupement des caractères identiques...
return "".join(
" %s" % " ".join((table[k], "0" * len(tuple(g))))
for (k, g) in groupby(binaire)
)[1:] # ... en supprimant le premier espace inutile
# binaire2unaire() |
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2024 Developpez Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.