0

我正在尝试在 python 中创建 vigenere 密码,但似乎存在问题。这是我的加密代码:

def encryption():
    plaintext=input("Please enter the message you wish to encode.")
    #This allows the user to enter the message they wish to encrypt.
    keyword=input("Please enter your keyword, preferably shorter than the plaintext.")
    #This allows the user to enter a keyword.
    encoded=""
    #This creates a string for the user to input the encrypted message to.
    while len(keyword)<len(plaintext):
        #This begins a while loop based on the fact that the length of the keyword is shorter than the length of the plaintext.
        keyword+=keyword
        #This repeats the keyword.
        if len(keyword)>len(plaintext):
            #This sees if the string length of the keyword is now longer than the string length of the plaintext.
            newkey=keyword[:len(plaintext)]
            #This cuts the string length of the keyword
    for c in range(len(plaintext)):
        char=ord(plaintext[c])
        temp=ord(keyword[c])
        newchar=char+temp
        if newchar>ord("Z"):
            newchar-=26
        newnewchar=chr(newchar)
        encoded+=newnewchar
    print(encoded)

我似乎找不到它的问题,但是当我输入明文“hello”和关键字“hi”时,它会出现以下符号:¶´º»½。我认为 for 循环中的添加可能太过分了。

4

3 回答 3

1

你需要了解 ord() 函数,chr() 是 ord() 的逆

 for i in range(300):
     print(str(i) + ' ' + chr(i))

如果不使用 Unicode 字符,可以使用字母字符串

alphabet = 'abcdefghijklmnopqrstuvwxyz'
for p,k in zip(plaintext,keyword): # you can directly iterate strings
    char = alphabet.index(p)
    temp = alphabet.index(k)
    newchar = char + temp
    if newchar > 25:
        newchar -= 25
    newchar = alphabet[newchar]
于 2014-11-05T09:22:55.523 回答
0

我不会只为您解决错误,因为这里还有许多其他需要改进的地方!
在运算符周围放置空格:a=b应该是a = b,与+,-等相同。

我发现使用函数参数比使用input. 您始终可以使用第二个函数来获取输入并加密输入:

def encryption(plaintext, keyword):
    pass  # (do nothing)

我让你写辅助函数。

我和大多数人通常将注释放在相应代码上方的行中。另外,不需要This每次都写,通常首选命令式。

现在让我们看看你的while循环。条件是len(keyword) < len(plaintext),里面你查len(keyword) > len(plaintext)。什么时候会发生?仅在最后一次迭代期间。所以将代码移出循环。
此外,你在里面做的事情if不需要if:(
any_string[:len(any_string) + n] == any_stringn积极的int)。
加上你从不使用newkey

所以我们可以将循环简化为:

# Begin a while loop based on the fact that the length of the keyword is
# shorter than the length of the plaintext.
while len(keyword) < len(plaintext):
    # Repeat the keyword.
    keyword += keyword

# Cut the string length of the keyword
keyword = keyword[:len(plaintext)]

这相当于:

# Do the operation once
txt_len = len(plaintext)
# Get a string just a bit longer than plaintext
# Otherwise we would have issues when plaintext is not a multiple
# of keyword
keyword *= txt_len // len(keyword) + 1
# Chop of the extra part
keyword = keyword[:txt_len]

请注意,当len(keyword) == 0.

现在进入for循环:
你可以使用zippolku 向你展示的那样,但我认为它现在太复杂了,并保留range. 您也可以使用字母表,但简单的算术可以解决问题:
alphabet.index(x) == ord(x) - ord('a'),所以在您的代码中:

char = ord(plaintext[c]) - ord('a')
temp = ord(keyword[c]) - ord('a')
newchar = char + temp
# Or simply:
newchar = ord(plaintext[c]) + ord(keyword[c]) - 194  # 2 * ord('a')

如果我们忽略大写字母,我们可以安全地替换

if newchar > 25:
    newchar -= 25
# With
newchar %= 25

最后: alphabet[i] == ord(i + ord('a'))

这是所有这些放在一起:

def encryption(plaintext, keyword):
    # Do the operation once
    txt_len = len(plaintext)

    # Get a string just a bit longer than plaintext
    # Otherwise we would have issues when plaintext is not a multiple
    # of keyword
    keyword *= txt_len // len(keyword) + 1  # // is floor division
    # Chop of the extra characters (if there are any)
    keyword = keyword[:txt_len]

    # Create a string to store the encrypted message
    encoded = ""

    # Now you should change this to work with capital letters
    for c in range(txt_len):
        # 194 = 2 * ord('a')
        newchar = ord(plaintext[c]) + ord(keyword[c]) - 194
        newchar %= 25
        encoded += chr(newchar + 97)  # 97 = ord('a')

    return encoded


def encrypt_input():
    # This function should use input to get plaintext and keyword
    # Then use encryption with those strings and print the result
    pass
于 2014-11-05T10:16:44.903 回答
0

事实上,加法太过分了,因为ord使用 ASCII(其中 A 为 65),而 de Vigenère 将 A 排在第一位。你可以减去ord('A')。该代码还假设所有字符都是大写字母。这是一个变体,它使用一些 Python 的库函数来执行任务。

import string, itertools
def encrypt(text, key='N'):     # default to rot13 (:
    '''Performs a Vigenere cipher of given plaintext and key'''
    result=[]
    key=key.upper()
    for plain,shift in itertools.izip(text,itertools.cycle(key)):
        shiftindex=string.ascii_uppercase.index(shift)
        shiftto=(string.ascii_uppercase[shiftindex:] +
                 string.ascii_uppercase[:shiftindex])
        trans=string.maketrans(string.ascii_letters,
                               shiftto.lower()+shiftto)
        result.append(plain.translate(trans))
    return ''.join(result)

一个更完整的变体可能只消耗字母的键,但如果你的字符串只包含字母,这会很好。我坚持使用 ASCII 字母的原因是,特定于语言环境的字母可能没有预期的顺序,也没有匹配的大小写(例如,德语 ß)。也完全可以只将键翻译成翻译表列表一次。

于 2014-11-05T11:02:35.097 回答