E07 - ROT13⚓︎
Le problème
Proposition 1⚓︎
def ROT13(nb_carac, texte, texte2):
for lettre in texte:
if 65 < ord(lettre) < 78 :
texte2 += chr(ord(lettre) + 13)
elif 77 < ord(lettre) < 91 :
texte2 += chr(ord(lettre) - 13)
elif 96 < ord(lettre) < 110 :
texte2 += chr(ord(lettre) + 13)
elif 109 < ord(lettre) < 123 :
texte2 += chr(ord(lettre) - 13)
else :
texte2 += lettre
return texte2
nb_carac = int(input())
texte = input()
texte2 = ""
print(ROT13(nb_carac, texte, texte2))
-
Très mauvais code.
-
texte2
ne devrait pas être passé en paramètre, mais initialisé dans la fonction. -
On préfère une liste pour faire des ajouts successifs ; quitte à tout coller à la fin en str.
-
Tous ces nombres ne veulent rien dire à qui ne sait pas !!! Il ne faut pas coder ainsi !!!
Proposition 2⚓︎
def ROT13(nb_caractère, chaine_caractère):
"""remplace les caractère de la chaine par des autre à 13 caractères de là.
puis renvoie la chaine de caractère.
Tous les caractères qui ne sont pas des lettres non accentuées de
l'alphabet sont laissés tels quels.
>>> ROT13(15, "Vive Prologin !")
'Ivir Cebybtva !'
"""
nouvelle_chaine_caractère = ""
for i in range(nb_caractère):
caractère = ord(chaine_caractère[i])
if caractère >= 65 and caractère <= 90:
if caractère > 77:
caractère -= 13
else:
caractère += 13
elif caractère >= 97 and caractère <= 122:
if caractère > 109:
caractère -= 13
else:
caractère += 13
nouvelle_chaine_caractère += chr(caractère)
return nouvelle_chaine_caractère
# test
import doctest
doctest.testmod()
# entrée
nb_caractère = int(input())
chaine_caractère = input()
# sortie
print(ROT13(nb_caractère, chaine_caractère))
- C'est mal d'utiliser des nombres sans explication : 65, 77, 99 ???
- C'est mal d'ajouter souvent des caractères à une chaine. Il vaut mieux ajouter à une liste, et faire un collage à la fin avec
"".join(la_liste)
- Bon doctest.
Proposition 3⚓︎
def ROT13(liste_chaine: list, chaine_chiffrée: list, compteur: int) -> list:
"""
Renvoie la chaine chiffrée, où les caractères alphabétique [A-Za-z] sont chiffrés avec ROT13 et tous les autres caractères sont inchangés.
>>> ROT13(["!", " ", "n", "i", "g", "o", "l", "o", "r", "P", " ", "e", "v", "i", "V"], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 0)
['I', 'v', 'i', 'r', ' ', 'C', 'e', 'b', 'y', 'b', 't', 'v', 'a', ' ', '!']
"""
Alphabet_maj = "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ"
Alphabet_min = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"
if liste_chaine == []:
return chaine_chiffrée
else:
if liste_chaine[-1] in Alphabet_maj:
chaine_chiffrée[compteur] = Alphabet_maj[ Alphabet_maj.index( liste_chaine[-1] ) + 13 ]
elif liste_chaine[-1] in Alphabet_min:
chaine_chiffrée[compteur] = Alphabet_min[ Alphabet_min.index( liste_chaine[-1] ) + 13 ]
else:
chaine_chiffrée[compteur] = liste_chaine[-1]
liste_chaine.pop()
return ROT13(liste_chaine, chaine_chiffrée, compteur + 1)
-
C'est très vilain d'utiliser des chaines de lettres pour l'alphabet ; ce n'est pas la méthode vue en classe !!!
-
Il manque un modulo 26, cela t'aurait évité d'écrire deux fois tes chaines de caractères. Dans le même esprit, tu aurais pu donner une chaine d'un seul alphabet ayant subi la rotation.
Proposition 4⚓︎
import doctest
def chiffre(texte: str) -> str:
"""
Renvoie le texte en ajoutant à l'indice de chaque lettres 13
>>> chiffre('abcd')
'nopq'
"""
message_chiffré = ""
for lettre in texte:
message_chiffré += chiffrage_lettre(lettre)
return message_chiffré
def chiffrage_lettre(lettre: str) -> str:
"""
Renvoie la lettre à l'indice de la lettre + la constante CONT_rot_13
>>> chiffrage_lettre('a')
'n'
"""
CONST_rot_13 = 13
if 'a' <= lettre <= 'z':
indice = ord(lettre) - ord('a') + CONST_rot_13
return chr(ord('a') + indice % 26)
elif 'A' <= lettre <= 'Z':
indice = ord(lettre) - ord('A') + CONST_rot_13
return chr(ord('A') + indice % 26)
else:
return lettre
import doctest
doctest.testmod()
# Entrée
nb_caractere_texte = int(input())
texte = input()
# Sorti
print(chiffre(texte))
-
Presque parfait.
-
inutile d'importer deux fois
doctest
, une fois suffit. -
C'est mieux de définir la fonction
chiffre
après l'autre, et pas avant. -
C'est mieux d'accumuler dans une liste, pour coller ensuite avec
"".join(...)
. Avec une chaine, le hash est recalculé à chaque ajout ; lent.
Proposition 5⚓︎
def ROT_treize(nb_caractères, text):
"""
Affiche le text codée
"""
for i in range(nb_caractères):
if ord('A') <= ord(text[i]) <= ord('Z'):
decode = chr(ord(text[i]) - ord('A') + 13)
if ord(decode) > 25:
decode = chr(ord(decode) - 26)
decode = chr(ord(decode) + ord('A'))
print(decode, end='')
elif ord('a') <= ord(text[i]) <= ord('z'):
decode = chr(ord(text[i]) - ord('a') + 13)
if ord(decode) > 25:
decode = chr(ord(decode) - 26)
decode = chr(ord(decode)+ ord('a'))
print(decode,end='')
else:
print(text[i], end='')
#Entrée
nb_caractères = int(input())
text = input()
#Sortie
ROT_treize(nb_caractères, text)
-
Tu peux utiliser
ROT13
comme identifiant, il faut juste ne pas commencer par un chiffre. -
Il serait mieux de découper ta grande fonction avec une ou plusieurs autres fonctions auxiliaires.
Proposition 6⚓︎
def ROT13(chaine: str, DECALAGE: int) -> list:
"""
Fonction renvoyant une liste contenant pour chaque indice un caratère décalé de DECALAGE.
>>> ROT13("Vive Prologin !", 13)
['I', 'v', 'i', 'r', ' ', 'C', 'e', 'b', 'y', 'b', 't', 'v', 'a', ' ', '!']
"""
liste_finale = [0 for _ in range(len(chaine))]
for i in range(len(chaine)):
# Cas de lettre minuscule
if ord('a') <= ord(chaine[i]) and ord(chaine[i]) <= ord('z'):
liste_finale[i] = chr((ord(chaine[i]) + DECALAGE - ord('a')) % 26 + ord('a'))
# Cas de lettre majuscule
elif ord('A') <= ord(chaine[i]) and ord(chaine[i]) <= ord('Z'):
liste_finale[i] = chr((ord(chaine[i]) + DECALAGE - ord('A')) % 26 + ord('A'))
# Cas autre caratère
else:
liste_finale[i] = chaine[i]
return liste_finale
# Entrées
nb_c = int(input())
chaine = input()
DECALAGE = 13
# Sortie
ans = ROT13(chaine, DECALAGE)
for k in range(len(ans)):
print(ans[k], end='')
# Test
import doctest
doctest.testmod()
-
Il aurait été bon de faire le collage avant le
return
, pour renvoyer unestr
et non unelist
. -
Ce n'est pas très propre d'initialiser la liste avec des entiers, pour y mettre progressivement des caractères ; cela fait un mélange interdit avec d'autres langages.
Corrigé du professeur⚓︎
"""
author: Franck CHAMBON
problem: https://prologin.org/train/2004/semifinal/rot13
"""
def _rot13(caractere: str) -> str:
"""Renvoie le caractère avec une rotation de 13 dans l'alphabet,
seulement si c'est une lettre, sinon inchangé.
>>> _rot13('c')
'p'
>>> _rot13('E')
'R'
>>> _rot13('!')
'!'
"""
if len(caractere) != 1:
raise ValueError(f"{len(caractere)} : mauvais nombre de caractères")
elif 'a' <= caractere <= 'z':
i = ord(caractere) - ord('a')
i += 13
if i >= 26:
i-= 26
return chr(ord('a') + i)
elif 'A' <= caractere <= 'Z':
i = ord(caractere) - ord('A')
i += 13
if i >= 26:
i-= 26
return chr(ord('A') + i)
else:
return caractere
def ROT13(texte: str) -> str:
"""Renvoie le texte chiffré avec la méthode ROT13.
>>> ROT13("Vive Prologin !")
'Ivir Cebybtva !'
"""
return "".join(map(_rot13, texte))
# Tests
import doctest
doctest.testmod()
# Entrée
longueur = int(input())
texte = input()
assert longueur == len(texte)
# Sortie
print(ROT13(texte))
map
La fonction map
permet d'appliquer la fonction _rot13
à tous les éléments de texte
.
On colle ensuite le résultat produit.
Il s'agit d'un style fonctionnel.
Fonction interne
Pour indiquer qu'une fonction est à usage interne, on peut la préfixer avec _
.
On l'utilise dans son module, on ne conseille pas son utilisation en dehors, sans l'interdire.
Variante
i += 13
if i >= 26:
i-= 26
pourrait être remplacé par
if i >= 13:
i -= 13
else:
i += 13