19

我正在尝试在 Python 中创建一个简单的 Caesar Cipher 函数,该函数根据用户的输入转换字母,并在最后创建一个最终的新字符串。唯一的问题是最终的密文仅显示最后一个移位字符,而不是包含所有移位字符的整个字符串。

这是我的代码:

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)
4

26 回答 26

57

我意识到这个答案并不能真正回答你的问题,但我认为它还是有帮助的。这是使用字符串方法实现凯撒密码的另一种方法:

def caesar(plaintext, shift):
    alphabet = string.ascii_lowercase
    shifted_alphabet = alphabet[shift:] + alphabet[:shift]
    table = string.maketrans(alphabet, shifted_alphabet)
    return plaintext.translate(table)

事实上,由于字符串方法是在 C 中实现的,我们将看到这个版本的性能有所提高。这就是我认为的“pythonic”方式。

于 2012-01-17T13:35:10.610 回答
20

您需要cipherText = ""在 for 循环开始之前移动。每次循环都在重置它。

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
于 2012-01-16T22:07:58.703 回答
6

这是@amillerrhodes 答案中代码的改进版本,它适用于不同的字母,而不仅仅是小写:

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)

使用示例:

>>> import string
>>> alphabets = (string.ascii_lowercase, string.ascii_uppercase, string.digits)
>>> caesar('Abc-xyZ.012:789?жñç', step=4, alphabets=alphabets)
'Efg-bcD.456:123?жñç'

参考资料:
上的文档str.maketrans
上的文档str.translate图书馆
的文档string

于 2019-02-08T10:10:09.587 回答
5

使用一些 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)
于 2016-01-03T16:34:22.493 回答
4

包括电池

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

Python 3 更新

好的文档

[现在rot_13] 编解码器提供了一个文本转换:a strto strmapping。str.encode()(仅产生字节输出)不支持它。

或者,换句话说,您必须encodecodecs模块导入并将其与要编码的字符串一起用作其第一个参数

from codecs import decode
...
    print(encode(phrase, 'rot13'))
于 2015-03-18T13:12:15.797 回答
3

正如其他人所指出的,您在 for 循环的迭代中重置了 cipherText 。在 for 循环开始之前放置 cipherText 将解决您的问题。

此外,还有另一种方法可以使用 Python 的标准库来解决这个问题。Python 标准库定义了一个函数 maketrans() 和一个对字符串进行操作的方法 translate。

函数 maketrans() 创建可与 translate 方法一起使用的转换表,以更有效地将一组字符更改为另一组字符。(引用自 Python 标准库的示例)。

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)
于 2013-04-07T06:23:10.797 回答
3

问题是您在每次循环迭代时将 cipherText 设置为空字符串,行

cipherText = ""

必须在循环之前移动。

于 2012-01-16T22:09:49.827 回答
2

在这里,一个更实用的方式:(如果你使用 shift i 编码,然后使用 -i 解码)

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 
        ])
于 2016-10-13T23:37:27.577 回答
1
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)

如果ch.isalpha()你能把finalLetter=ch.

您应该删除该行:cipherText = ""

干杯。

于 2012-01-16T22:15:56.720 回答
1

正如@I82much 所说,您需要cipherText = ""跳出 for 循环。将其放在函数的开头。此外,您的程序有一个错误,当您输入大写字母时,它会导致它产生加密错误。尝试:

    if ch.isalpha(): 
        finalLetter = chr((ord(ch.lower()) - 97 + shift) % 26 + 97)
于 2012-01-17T02:47:48.607 回答
1

使用循环生成器:

import string
from itertools import cycle


def caesarCipherEncryptor(s, key):
    def generate_letters():
        yield from cycle(string.ascii_lowercase)
    
    def find_next(v, g, c):
        # Eat up characters until we arrive at the plaintext character
        while True:
            if v == next(g):
                break
        
        # Increment the plaintext character by the count using the generator
        try:
            for _ in range(c):
                item = next(g)
            return item
        except UnboundLocalError:
            return v

    return "".join([find_next(i, generate_letters(), key) for i in s])

# Outputs
>>> caesarCipherEncryptor("xyz", 3)
>>> 'abc'
于 2021-01-18T16:35:12.697 回答
1
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()
于 2017-10-12T16:32:19.727 回答
1

例如,解码字符串:

" uo jxuhu! jxyi yi qd unqcfbu ev q squiqh syfxuh. muhu oek qrbu je tusetu yj? y xefu ie! iudt cu q cuiiqwu rqsa myjx jxu iqcu evviuj!" .

此消息的偏移量为 10

下面的代码:

import string
alphabet = list(string.ascii_lowercase)
print(alphabet, len(alphabet))
messege = "xuo jxuhu! jxyi yi qd unqcfbu ev q squiqh syfxuh. muhu oek qrbu je tusetu yj? y xefu ie! iudt cu q cuiiqwu rqsa myjx jxu iqcu evviuj!"
messege_split = messege.split()
print(messege_split)

encrypted_messege = ""
position = 0
for i in messege_split:
    for j in i:
        if ord(j) < 65:
            encrypted_messege += j
        else:         
            for k in alphabet:
                if j == k:
                    position = alphabet.index(k)
                    if (position + 10) >= len(alphabet):
                        encrypted_messege += alphabet[abs((position + 10) - len(alphabet))]
                    else:
                        encrypted_messege += alphabet[position + 10]
    encrypted_messege += " "

print(encrypted_messege)

解码字符串:

“嘿,这是凯撒密码的一个例子。你能解码它吗?我希望如此!用相同的偏移量给我发回一条消息!”

试试看!

于 2020-07-09T16:40:02.770 回答
1
>>> 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!'
于 2017-08-21T20:11:56.390 回答
1
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 !@#$%^&*()_+-
于 2019-01-17T11:52:01.283 回答
1

我很难记住 char 到 int 的转换,所以可以优化

def decryptCaesar(encrypted, shift):
    minRange = ord('a')
    decrypted = ""
    for char in encrypted:
        decrypted += chr(((ord(char) - minRange + shift) % 26) + minRange)

    return decrypted
于 2017-09-29T20:51:40.953 回答
0
from string import ascii_lowercase as alphabet

class CaesarCypher:
    alpha_len = len(alphabet)
    min_guess_rate = 0.2

加密和解密是一回事。例如,当您想使用 shift 10 进行解密时,这意味着您可以使用 shift 26 - 10 对其进行加密。在这种情况下,如果您要移动整个字母表,则循环将重复,它将是相同的。同样在这里我已经进行了大写和非字符

    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)

所有加密最多都在这里。

    def _encrypt_letter(self, letter, offset=0):
        position = (alphabet.find(letter) + offset) % self.alpha_len
        return alphabet[position]

这部分用于 broot force 并通过字典频率猜测。

    @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
于 2016-09-08T09:52:43.117 回答
0
def encrypt(text,shift):
    '''
    INPUT: text as a string and an integer for the shift value.
    OUTPUT: The shifted text after being run through the Caeser cipher.
    '''

    # Create a placeholder list
    encrypted_text = list(range(len(text)))

    alphabet = string.ascii_lowercase

    # Create shifted alphabet
    first_half = alphabet[:shift]
    second_half = alphabet[shift:]
    shifted_alphabet = second_half+first_half

    for i,letter in enumerate(text.lower()):

        # Check for spaces or punctuation
        if letter in alphabet:
            # Find the original index position
            original_index = alphabet.index(letter)

            # Shifted letter
            new_letter = shifted_alphabet[original_index]

            encrypted_text[i] = new_letter

        # Punctuation or space
        else:
            encrypted_text[i] = letter

    return ''.join(encrypted_text)
于 2020-05-11T18:27:15.613 回答
0

代码很大,但是很容易理解。我觉得很适合你的情况。

alphabet = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"
class CaesarCipher(object):    
    def __init__(self, shift):
        self.shift = shift
    def encode(self, str):
        encode = ''
        str = str.lower()
        for i in str:
            if i in alphabet:
                encode += alphabet[alphabet.index(i) + self.shift]
            else:
                encode += i
    
        return encode.upper()


    def decode(self, str):
        decode = ''
        str = str.lower()
        for i in str:
            if i in alphabet:
                decode += alphabet[alphabet.index(i) - self.shift]
            else:
                decode += i
        return decode.upper()
    
于 2020-07-02T03:01:05.257 回答
0

ord这个解决方案在不使用函数的情况下更直观:

def caesar_cipher(raw_text, key):
    alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    shifted_alphabet = alphabet[26-key:]+alphabet[0:(26-key)]
    cipher_text = ""
    for i in range(len(raw_text)):
        char = raw_text[i]
        idx = alphabet.find(char.upper())
        if idx == -1:
            cipher_text = cipher_text + char
        elif char.islower():
            cipher_text = cipher_text + shifted_alphabet[idx].lower()
        else:
            cipher_text = cipher_text + shifted_alphabet[idx] 
    return(cipher_text)

还有一个例子:

plain_text = "The quick brown fox jumps over the lazy dog!"
caesar_cipher(plain_text,3)

我们得到:

'Qeb nrfzh yoltk clu grjmp lsbo qeb ixwv ald!'

如果我们要解密它:

caesar_cipher(caesar_cipher(plain_text,3),26-3)

我们得到:

'The quick brown fox jumps over the lazy dog!'

更多细节在这里:https ://predictivehacks.com/caesar-cipher-in-python/

于 2020-08-18T21:01:21.463 回答
0

根据我的说法,这个答案对你有用:

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)

此功能根据给定的键将所有字母向右移动。

于 2017-04-18T06:42:02.607 回答
0
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
于 2017-03-29T13:01:37.650 回答
0

为什么不在 shift 输入上使用 reverse 函数,并将 plain_text 与 shift 连接起来,作为密文输入:

Plain = int(input("enter a number ")) 
Rev = plain[::-1]
Cipher = " ".join(for cipher_text in Rev) 
于 2017-10-12T16:45:57.667 回答
0

使用map

def caesar(text, key):
    return ''.join(map(lambda c: 
        chr((ord(c.lower()) - ord('a') + key) % 26 + ord('a')) if c.isalpha() else ''
    , text))

于 2020-07-13T20:13:54.310 回答
-1
key = 3

def wub():
    def choice():
        choice = input("Do you wish to Encrypt of Decrypt?")
        choice = choice.lower()
        if choice == "e" or "encrypt":
            return choice
        elif choice == "d" or "decrypt":
            return choice
        else:
            print("Invalid response, please try again.")
            choice()

    def message():
        user = input("Enter your message: ")
        return user

    def waffle(choice, message, key):
        translated = ""
        if choice == "e" or "encrypt":
            for character in message:
                num = ord(character)
                num += key
                translated += chr(num)

                derek = open('Encrypted.txt', 'w')
                derek.write(translated)
            derek.close()
            return translated
        else:
            for character in message:
                num = ord(character)
                num -= key
                translated += chr(num)
            return translated

    choice = choice() #Runs function for encrypt/decrypt selection. Saves choice made.
    message = message() #Run function for user to enter message. Saves message.
    final = waffle(choice, message, key) #Runs function to translate message, using the choice, message and key variables)
    print("\n Operation complete!")
    print(final)

wub()
于 2016-11-09T13:40:09.970 回答
-1

凯撒密码

message = str(input("Enter you message:"))
shift = int(input("Enter a number:"))
# encode

stringValue = [ord(message) - 96 for message in message]
print(stringValue)
encode_msg_val = []


[encode_msg_val.append(int(stringValue[i])+shift) for i in 
range(len(stringValue))]

encode_msg_array = []
for i in range(len(encode_msg_val)):
    encode_val = encode_msg_val[i] + 96
    encode_msg_array.append(chr(encode_val))

print(encode_msg_array)
encode_msg = ''.join(encode_msg_array)


# dedcode

[deocde_msg_val = [ord(encode_msg) - 96 for encode_msg in encode_msg]

decode_val = []
[decode_val.append(deocde_msg_val[i] - shift) for i in 
range(len(deocde_msg_val))]

decode_msg_array = []
[decode_msg_array.append(decode_val[i] + 96) for i in range(len(decode_val))]

decode_msg_list = []
[decode_msg_list.append(chr(decode_msg_array[i])) for i in 
range(len(decode_msg_array))]

decode_msg = ''.join(decode_msg_list)
print(decode_msg)
于 2020-09-04T11:52:02.000 回答