Comment fonctionne le code
La boucle lit le texte caractère par caractère. ord() transforme une lettre en nombre : ord("A") vaut 65 et ord("a") vaut 97. En retirant cette base, on obtient le rang de la lettre dans l’alphabet, de 0 à 25.
Une fois le décalage ajouté, % 26 revient au début de l’alphabet : avec un décalage de 3, le Z tombe sur le C. chr() repasse ensuite du nombre à la lettre. Si le chiffre lui-même est nouveau pour vous, le guide l’explique sans code.
Les espaces, la ponctuation et les chiffres passent par la branche else sans changer. Il en va de même pour les lettres accentuées, grâce à isascii(). Sans ce test, é compte comme une lettre et, avec un décalage de 3, devient j : impossible ensuite de retrouver le é d’origine.
Déchiffrer en Python
Inutile d’écrire une seconde fonction. Déchiffrer revient à décaler dans l’autre sens : il suffit de passer un nombre négatif.
print(caesar("Erqmrxu à wrxv !", -3))# Bonjour à tous !Cela fonctionne parce que le % de Python ne donne jamais de négatif ici : (0 - 3) % 26 vaut 23, et le A revient au X. En C, Java et JavaScript, on obtiendrait -3, d’où une étape de plus dans la version JavaScript.
Un programme avec saisie utilisateur
Beaucoup d’exercices demandent un programme qui lit le texte et le décalage au clavier. Ajoutez ceci sous la fonction :
text = input("Texte : ")shift = int(input("Décalage : "))mode = input("Chiffrer ou déchiffrer ? (c/d) : ") if mode == "d": shift = -shift print(caesar(text, shift))input() renvoie toujours une chaîne : le décalage doit donc passer par int(). Si l’on tape un mot à la place d’un nombre, Python s’arrête sur une ValueError.
Casser le code par force brute
Avec 26 lettres, il n’y a que 25 décalages à essayer, et une courte boucle suffit pour lire un message sans la clé. Cherchez dans la sortie la ligne qui a du sens :
def crack(text): for shift in range(1, 26): print(shift, caesar(text, -shift)) crack("Erqmrxu à wrxv !")# 1 Dqplqwt à vqwu !# 2 Cpokpvs à upvt !# 3 Bonjour à tous !# ...L’article sur l’attaque par force brute va plus loin, et le casseur en ligne fait la même chose dans votre navigateur.
Une version plus courte avec str.translate
Une fois la boucle comprise, vous pouvez la remplacer par une table de traduction. str.maketrans() associe chaque lettre à sa version décalée, et translate() applique la table à tout le texte. Ici non plus, les accents ne bougent pas.
from string import ascii_lowercase as lower, ascii_uppercase as upper def caesar(text, shift): shift %= 26 table = str.maketrans( lower + upper, lower[shift:] + lower[:shift] + upper[shift:] + upper[:shift], ) return text.translate(table)Le résultat est identique, et c’est souvent plus rapide sur un long texte, car la table n’est construite qu’une fois. Pour un premier exercice, la boucle reste plus facile à expliquer.
Autres alphabets et chiffres
Pour décaler autre chose que A à Z, gardez l’alphabet dans une chaîne et cherchez chaque caractère avec index(). Ici, l’alphabet comprend aussi les chiffres :
ALPHABET = "abcdefghijklmnopqrstuvwxyz0123456789" def caesar_alphabet(text, shift): result = "" for char in text: letter = char.lower() if letter in ALPHABET: index = (ALPHABET.index(letter) + shift) % len(ALPHABET) new = ALPHABET[index] result += new.upper() if char.isupper() else new else: result += char return result print(caesar_alphabet("Salle 101", 3))# Vdooh 434Le retour au début dépend désormais de len(ALPHABET), et il suffit de modifier la chaîne pour y ajouter é, è ou ç. Notre outil de chiffre de César propose aussi des alphabets tout prêts pour comparer les résultats.
Chiffrer un fichier texte
Lisez le fichier, passez son contenu à la fonction et écrivez le résultat dans un nouveau fichier. Avec encoding="utf-8", les accents restent intacts sur tous les systèmes.
with open("message.txt", encoding="utf-8") as source: text = source.read() with open("encrypted.txt", "w", encoding="utf-8") as target: target.write(caesar(text, 3))Le même chiffre sous forme de classe
Une classe devient utile si vous réutilisez souvent la même clé, ou si un cours exige du code orienté objet. Elle garde le décalage et s’appuie sur la fonction du haut de la page :
class CaesarCipher: def __init__(self, shift=3): self.shift = shift def encrypt(self, text): return caesar(text, self.shift) def decrypt(self, text): return caesar(text, -self.shift) cipher = CaesarCipher(5)print(cipher.encrypt("Bonjour à tous !"))# Gtsotzw à ytzx !Tester votre code
Quelques lignes assert repèrent la plupart des bugs : dépassement du Z, respect de la casse, ponctuation conservée et retour au texte d’origine. Si tout va bien, le programme affiche OK.
assert caesar("ABC", 3) == "DEF"assert caesar("xyz", 3) == "abc"assert caesar("Hello, World!", 5) == "Mjqqt, Btwqi!"assert caesar(caesar("Python", 7), -7) == "Python"assert caesar("A", 26) == "A"assert caesar("é", 3) == "é"print("OK")Erreurs fréquentes
Le grand classique consiste à écrire chr(ord(char) + shift) sans modulo : avec un décalage de 3, le Z devient alors le symbole ]. Autre erreur courante, la base 65 appliquée à toutes les lettres, qui abîme les minuscules. Et sans int() autour de input(), Python s’arrête sur une TypeError au moment d’ajouter le décalage.
Questions fréquentes
Quelle version de Python faut-il ?
Python 3.7 ou plus récent, puisque isascii() date de cette version. Nous avons exécuté le code de cette page sous Python 3.9. Aucun paquet supplémentaire n’est nécessaire.
Puis-je protéger de vraies données avec ce code ?
Non. La boucle ci-dessus le casse en quelques secondes. Gardez-le pour apprendre et pour les énigmes, et protégez mots de passe et données privées avec le chiffrement moderne d’une librairie maintenue.
Comment vérifier mon résultat ?
Saisissez le même texte et le même décalage dans notre outil de chiffre de César et comparez. Vous pouvez aussi appeler l’API REST gratuite depuis vos tests.