web-dev-qa-db-fra.com

Fonction de chiffrement César en Python

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)
14
user1063450

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».

39
amillerrhodes

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
15
I82Much

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)
3
alvas

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)
2
Wasif Hyder

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.

2
Dmitry Polyanitsa

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 de str à str. Il n'est pas supporté par str.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'))
2
gboffi

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)
1
Joel Cornett
>>> 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!'
1
Aziz Alto
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()
1
StudentPie

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 
        ])
1
Jamesits
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é.

0
JDL

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) 
0
Olafusi Emmanuel
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
0
dan

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.

0
Rohit-Pandey

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

0
Georgy
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
0
Eugene Yalansky
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 !@#$%^&*()_+-
0
Ari Victor

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
0
Michael Luong