J'essaie de créer une simple fonction de chiffrement César en Python qui décale les lettres en fonction des entrées de l'utilisateur et crée une dernière chaîne, la dernière. Le seul problème est que le texte chiffré final ne montre que le dernier caractère décalé, pas une chaîne entière avec tous les caractères décalés.
Voici mon code:
plainText = raw_input("What is your plaintext? ")
shift = int(raw_input("What is your shift? "))
def caesar(plainText, shift):
for ch in plainText:
if ch.isalpha():
stayInAlphabet = ord(ch) + shift
if stayInAlphabet > ord('z'):
stayInAlphabet -= 26
finalLetter = chr(stayInAlphabet)
cipherText = ""
cipherText += finalLetter
print "Your ciphertext is: ", cipherText
return cipherText
caesar(plainText, shift)
Je me rends compte que cette réponse ne répond pas vraiment à votre question, mais je pense que c'est utile quand même. Voici une autre façon d'implémenter le chiffrement César avec des méthodes de chaîne:
def caesar(plaintext, shift):
alphabet = string.ascii_lowercase
shifted_alphabet = alphabet[shift:] + alphabet[:shift]
table = string.maketrans(alphabet, shifted_alphabet)
return plaintext.translate(table)
En fait, étant donné que les méthodes de chaîne sont implémentées en C, nous assisterons à une augmentation des performances avec cette version. C’est ce que j’aimerais considérer comme la méthode «pythonique».
Vous devez déplacer cipherText = ""
avant le début de la boucle for. Vous le réinitialisez à chaque fois dans la boucle.
def caesar(plainText, shift):
cipherText = ""
for ch in plainText:
if ch.isalpha():
stayInAlphabet = ord(ch) + shift
if stayInAlphabet > ord('z'):
stayInAlphabet -= 26
finalLetter = chr(stayInAlphabet)
cipherText += finalLetter
print "Your ciphertext is: ", cipherText
return cipherText
En utilisant quelques astuces numériques ascii:
# See http://ascii.cl/
upper = {ascii:chr(ascii) for ascii in range(65,91)}
lower = {ascii:chr(ascii) for ascii in range(97,123)}
digit = {ascii:chr(ascii) for ascii in range(48,58)}
def ceasar(s, k):
for c in s:
o = ord(c)
# Do not change symbols and digits
if (o not in upper and o not in lower) or o in digit:
yield o
else:
# If it's in the upper case and
# that the rotation is within the uppercase
if o in upper and o + k % 26 in upper:
yield o + k % 26
# If it's in the lower case and
# that the rotation is within the lowercase
Elif o in lower and o + k % 26 in lower:
yield o + k % 26
# Otherwise move back 26 spaces after rotation.
else: # alphabet.
yield o + k % 26 -26
x = (''.join(map(chr, ceasar(s, k))))
print (x)
Comme l'ont souligné d'autres personnes, vous réinitialisiez le texteCipherText dans l'itération de la boucle for. Placer cipherText avant le début de la boucle for résoudra votre problème.
En outre, il existe une autre approche pour résoudre ce problème à l'aide de la bibliothèque Standard de Python. La bibliothèque standard Python définit une fonction maketrans () et une méthode de traduction qui fonctionne sur les chaînes.
La fonction maketrans () crée des tables de traduction pouvant être utilisées avec la méthode de traduction pour changer plus efficacement un jeu de caractères. (Citation tirée de The Python Standard Library par Example).
import string
def caesar(plaintext, shift):
shift %= 26 # Values greater than 26 will wrap around
alphabet_lower = string.ascii_lowercase
alphabet_upper = string.ascii_uppercase
shifted_alphabet_lower = alphabet_lower[shift:] + alphabet_lower[:shift]
shifted_alphabet_upper = alphabet_upper[shift:] + alphabet_upper[:shift]
alphabet = alphabet_lower + alphabet_upper
shifted_alphabet = shifted_alphabet_lower + shifted_alphabet_upper
table = string.maketrans(alphabet, shifted_alphabet)
return plaintext.translate(table)
Le problème est que vous définissez cipherText sur vider la chaîne à chaque itération du cycle, la ligne
cipherText = ""
doit être déplacé avant la boucle.
Batteries incluses
while 1:
phrase = raw_input("Could you please give me a phrase to encrypt?\n")
if phrase == "" : break
print "Here it is your phrase, encrypted:"
print phrase.encode("rot_13")
print "Have a Nice afternoon!"
https://docs.python.org/2/library/codecs.html#python-specific-encodings
Mise à jour Python 3
Les beaux documents dire
[Maintenant, le codec
rot_13
] fournit une transformation de texte: un mappage destr
àstr
. Il n'est pas supporté parstr.encode()
(qui ne produit que des octets en sortie).
Ou, en d'autres termes, vous devez importer encode
à partir du module codecs
et l'utiliser avec la chaîne à coder comme premier argument
from codecs import decode
...
print(encode(phrase, 'rot13'))
Comme @ I82much l'a dit, vous devez placer cipherText = ""
en dehors de votre boucle for. Placez-le au début de la fonction. En outre, votre programme a un bogue qui lui permet de générer des erreurs de cryptage lorsque vous recevez des lettres majuscules. Essayer:
if ch.isalpha():
finalLetter = chr((ord(ch.lower()) - 97 + shift) % 26 + 97)
>>> def rotate(txt, key):
... def cipher(i, low=range(97,123), upper=range(65,91)):
... if i in low or i in upper:
... s = 65 if i in upper else 97
... i = (i - s + key) % 26 + s
... return chr(i)
... return ''.join([cipher(ord(s)) for s in txt])
# test
>>> rotate('abc', 2)
'cde'
>>> rotate('xyz', 2)
'zab'
>>> rotate('ab', 26)
'ab'
>>> rotate('Hello, World!', 7)
'Olssv, Dvysk!'
def encrypt():
plainText = input("What is your plaintext? ")
shift = int(input("What is your shift? "))
cipherText = ""
for ch in plainText:
if ch.isalpha():
stayInAlphabet = ord(ch) + shift
if stayInAlphabet > ord('z'):
stayInAlphabet -= 26
finalLetter = chr(stayInAlphabet)
cipherText += finalLetter
print ("Your ciphertext is: ", cipherText,"with a shift of",shift)
def decrypte():
encryption=input("enter in your encrypted code")
encryption_shift=int(input("enter in your encryption shift"))
cipherText1 = ""
for c in encryption:
if c.isalpha():
stayInAlphabet1 = ord(c) - encryption_shift
if stayInAlphabet1 > ord('z'):
stayInAlphabet1 += 26
finalLetter1 = chr(stayInAlphabet1)
cipherText1 += finalLetter1
print ("Your ciphertext is: ", cipherText1,"with negative shift of",encryption_shift)
from tkinter import *
menu=Tk()
menu.title("menu")
menu.geometry("300x300")
button1= Button(menu,text="encrypt",command=encrypt)
button1.pack()
button2= Button(menu,text="decrypt",command=decrypte)
button2.pack()
button3= Button(menu,text="exit",command=exit)
button3.pack()
menu.mainloop()
Ici, une manière plus fonctionnelle: (Si vous utilisez shift i pour encoder, utilisez ensuite -i pour décoder)
def ceasar(story, shift):
return ''.join([ # concentrate list to string
(lambda c, is_upper: c.upper() if is_upper else c) # if original char is upper case than convert result to upper case too
(
("abcdefghijklmnopqrstuvwxyz"*2)[ord(char.lower()) - ord('a') + shift % 26], # rotate char, this is extra easy since Python accepts list indexs below 0
char.isupper()
)
if char.isalpha() else char # if not in alphabet then don't change it
for char in story
])
plainText = raw_input("What is your plaintext? ")
shift = int(raw_input("What is your shift? "))
def caesar(plainText, shift):
for ch in plainText:
if ch.isalpha():
stayInAlphabet = ord(ch) + shift
if stayInAlphabet > ord('z'):
stayInAlphabet -= 26
finalLetter = chr(stayInAlphabet)
#####HERE YOU RESET CIPHERTEXT IN EACH ITERATION#####
cipherText = ""
cipherText += finalLetter
print "Your ciphertext is: ", cipherText
return cipherText
caesar(plainText, shift)
En tant qu'autre si if ch.isalpha()
vous pouvez mettre finalLetter=ch
.
Vous devez supprimer la ligne: cipherText = ""
À votre santé.
Pourquoi ne pas utiliser la fonction reverse sur l'entrée de décalage et joindre le plain_text au décalage et le saisir comme texte chiffré
Plain = int(input("enter a number "))
Rev = plain[::-1]
Cipher = " ".join(for cipher_text in Rev)
import string
wrd=raw_input("Enter Word").lower()
fwrd=""
for let in wrd:
fwrd+=string.ascii_lowercase[(string.ascii_lowercase).index(let)+3]
print"Original Word",wrd
print"New Word",fwrd
selon moi, cette réponse vous est utile:
def casear(a,key):
str=""
if key>26:
key%=26
for i in range(0,len(a)):
if a[i].isalpha():
b=ord(a[i])
b+=key
#if b>90: #if upper case letter ppear in your string
# c=b-90 #if upper case letter ppear in your string
# str+=chr(64+c) #if upper case letter ppear in your string
if b>122:
c=b-122
str+=chr(96+c)
else:
str+=chr(b)
else:
str+=a[i]
print str
a=raw_input()
key=int(input())
casear(a,key)
Cette fonction décale toute lettre à droite selon la touche donnée.
Ceci est une version améliorée du code dans la réponse de @amillerrhodes qui fonctionne avec différents alphabets, pas seulement en minuscules:
def caesar(text, step, alphabets):
def shift(alphabet):
return alphabet[step:] + alphabet[:step]
shifted_alphabets = Tuple(map(shift, alphabets))
joined_aphabets = ''.join(alphabets)
joined_shifted_alphabets = ''.join(shifted_alphabets)
table = str.maketrans(joined_aphabets, joined_shifted_alphabets)
return text.translate(table)
Exemple d'utilisation:
>>> import string
>>> alphabets = (string.ascii_lowercase, string.ascii_uppercase, string.digits)
>>> caesar('Abc-xyZ.012:789?жñç', step=4, alphabets=alphabets)
'Efg-bcD.456:123?жñç'
Références:
Docs sur str.maketrans
.
Docs sur str.translate
.
Docs sur la bibliothèque string
from string import ascii_lowercase as alphabet
class CaesarCypher:
alpha_len = len(alphabet)
min_guess_rate = 0.2
Le cryptage et le décryptage sont identiques. lorsque vous souhaitez décrypter, par exemple avec le décalage 10, cela signifie que vous pouvez le chiffrer avec les décalages 26 à 10. Dans ce cas, le cycle sera répété si vous voulez décaler tout l'alphabet, il sera identique. Aussi ici j'ai procéder en majuscules et non caractères
def __call__(self, text, offset, encrypt=True):
if not encrypt:
offset = self.alpha_len - offset
result = []
for letter in text:
if not letter.isalpha():
result.append(letter)
continue
letter_to_process = letter.lower()
processed_letter = self._encrypt_letter(letter_to_process, offset)
if letter.isupper():
processed_letter = processed_letter.upper()
result.append(processed_letter)
return ''.join(result)
tout le cryptage va ici tout au plus.
def _encrypt_letter(self, letter, offset=0):
position = (alphabet.find(letter) + offset) % self.alpha_len
return alphabet[position]
cette partie est pour force de frappe et devinez par la fréquence du dictionnaire.
@staticmethod
def __how_many_do_i_know(text):
clean_words = filter(lambda x: x.isalpha(), text.split())
clean_words = ['\'{}\''.format(x) for x in clean_words]
cursor = conn.cursor()
query = 'SELECT COUNT(*) FROM mydictionary WHERE Word IN ({})'.format(",".join(clean_words))
cursor.execute(query)
response = cursor.fetchone()[0]
return response / len(clean_words)
def guess_encode(self, text):
options = [self(text, offset, encrypt=False) for offset in range(self.alpha_len)]
best_option = [self.__how_many_do_i_know(option) for option in options]
best_key, guess_rate = max(enumerate(best_option), key=lambda x: x[-1])
guess_text = options[best_key]
return best_key, guess_rate, guess_text
message = 'The quick brown fox jumped over the lazy dog. 1234567890 !@#$%^&*()_+-'
encrypted = ''.join(chr(ord(char)+3) for char in message)
decrypted = ''.join(chr(ord(char)-3) for char in encrypted)
print(encrypted)
print(decrypted)
# Wkh#txlfn#eurzq#ir{#mxpshg#ryhu#wkh#od}|#grj1#456789:;<3#$C&'(a)-+,b.0
# The quick brown fox jumped over the lazy dog. 1234567890 !@#$%^&*()_+-
J'ai du mal à me souvenir des conversions caractère à caractère int, cela pourrait donc être optimisé
def decryptCaesar(encrypted, shift):
minRange = ord('a')
decrypted = ""
for char in encrypted:
decrypted += chr(((ord(char) - minRange + shift) % 26) + minRange)
return decrypted