使 Vigenére 加密/解密跳过空格

Making Vigenére encryption / decryption skip whitespace

我使用维吉尼亚密码制作了一个基于菜单的加密工具。目前程序对空格进行了加密,我怎样才能让程序跳过空格。

#creating variables to be used
text_in_use = ''
encrypt_key = ''
decrypt_key = ''

#function to encypypt input text
def encrypt(plaintext, key):
    keyLength = len(key)
    keyAsIntegers = [ord(i) for i in key] #create list with the ASCII value for each charachter in key
    plaintextAsIntegers = [ord(i) for i in plaintext] #create list with the ASCII value for each charachter in text
    encyptedtext = '' 
    for i in range(len(plaintextAsIntegers)): #
        encryptvalue = (plaintextAsIntegers[i] + keyAsIntegers[i % keyLength]) % 26 #execute encryption or characters according to vigenere definition
        encyptedtext += chr(encryptvalue + 65)
    return encyptedtext #return the encyptes tex

#function to decrypt the encrypted text
def decrypt(encyptedtext, key):
    keyLength = len(key)
    keyAsIntegers = [ord(i) for i in key] #create list with the ASCII value for each charachter in key
    encryptedTextAsIntegers = [ord(i) for i in encyptedtext] #create list with the ASCII value for each charachter in text
    plaintext = ''
    for i in range(len(encryptedTextAsIntegers)):
        value = (encryptedTextAsIntegers[i] - keyAsIntegers[i % keyLength]) % 26 #decryption of encrypted characters
        plaintext += chr(value + 65)
    return plaintext #return decrypted text

#check if user input is valid
def check_value(userEntry):
    while True:
        try: #check if userinput is an integer
            userInput = int(input(userEntry))
            if userInput not in range(1,6): #check if userinput is in valid range
                print("Invalid choice, valid choices are 1-5! Try again! \n")
        except ValueError:
            print("Invalid choice! Input can't be empty or a string! \n")
            print("""1: Input text to work with
2: Print the current text
3: Encrypt the current text
4: Decrypt the current text
5: Exit""")
        else:
            return userInput #return valid userinput


def menu():
    while True:
        print("""1: Input text to work with
2: Print the current text
3: Encrypt the current text
4: Decrypt the current text
5: Exit""")

        choice = check_value("Enter Choice: ")

        if choice == 1: #allows user to input text for use
            text_in_use = str(input("Enter Text: ")).upper()
            print("Text is set to:",text_in_use,"\n")
        elif choice == 2: #prints set text
            print("Your text:",text_in_use,"\n") 
        elif choice == 3: #ask user to set encryptionkey
            encrypt_key = str(input("Enter an encryptionkey: ")).upper()
            text_in_use = encrypt(text_in_use, encrypt_key)
            print("Your text:", text_in_use)
        elif choice == 4: #ask user for decryptionkey
            decrypt_key = str(input("Enter a the decryptionkey: ")).upper()
            text_in_use = decrypt(text_in_use, decrypt_key)
            print("Your text:", text_in_use)
        elif choice == 5:
            exit()

menu()

我希望程序像它已经运行的那样运行,但它应该跳过加密中的空格。

如:

"HELLO MY MAN" --> encryption(key = asd) --> "HWOLG MQ MSQ"

换句话说,加密文本中的空格应该仍然存在。

当明文为 "HELLO MY MAN" 且密钥为 "asd" 时,不确定你是如何得到 "HWOLG MQ MSQ" 的。我得到了别的东西。

无论如何,也许是这样的:

def encrypt(plaintext, key):
    from itertools import cycle
    from string import ascii_uppercase as alphabet

    offset = ord("A")

    key_char = cycle(key)

    encrypted_plaintext = ""
    for char in plaintext:
        # If the current character is any kind of whitespace...
        if char.isspace():
            # Append it to the final string with no changes.
            encrypted_plaintext += char
        else:
            # The character is not whitespace, so you have to encrypt it.
            char_sum = ord(char) + ord(next(key_char))
            char_sum_wrapped = char_sum % len(alphabet)
            encrypted_plaintext += chr(char_sum_wrapped + offset)
    return encrypted_plaintext

如果当前字符是白色space,只需将其附加到最后的字符串而不做任何更改。 str.isspace return 如果字符串中的每个字符(当前字符)都是某种白色,则为真space(space、制表符、换行符、回车return,等)。

我尽量避免使用索引和硬编码数字,所以我改变了一些东西。例如,我没有像您那样在执行任何其他操作之前将明文和密钥中的所有字符都转换为整数,而是只转换循环中的字符。顺便说一句,循环也不同——我迭代明文中的字符,而不是执行基于范围的 for 循环,然后将 i 视为当前字符的索引。其余的基本相同(除了 key_charitertools.cycle 的东西,请阅读下面我的笔记)。

另一件需要注意的事情是,在这个实现中,key_char 迭代器只有在明文中的当前字符不是白色时才会前进space - 但是,您可以无论如何都希望它前进。只是要记住一些事情。

没关系,这似乎是此密码所需的行为。

此外,请注意,您的程序以以下几行开头:

#creating variables to be used
text_in_use = ''
encrypt_key = ''
decrypt_key = ''

它们根本没有贡献,您可以安全地删除它们。

编辑 - 更多信息:

itertools.cycle 是一个函数,给定一个可迭代对象(如字符串或列表),return 是一个迭代器,它产生该可迭代对象中的元素。例如:

>>> from itertools import cycle
>>> char_iterator = cycle("ABC")
>>> next(char_iterator)
'A'
>>> next(char_iterator)
'B'
>>> next(char_iterator)
'C'
>>> next(char_iterator)
'A'
>>> next(char_iterator)
'B'
>>> next(char_iterator)
'C'
>>> next(char_iterator)
'A'
>>> 

如您所见,循环无限期地重复。出于这个原因,我选择使用 itertools.cycle 来替换原始代码中的 keyAsIntegers[i % keyLength]

string.ascii_uppercase 只是一个由 A-Z 之间的所有大写字母组成的字符串。在我的代码中,我导入 ascii_uppercase 并在同一行中将其重命名为 alphabet,但它们是相同的。

>>> from string import ascii_uppercase as alphabet
>>> alphabet
'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
>>> 

您可以忽略白色 space 的加密方法,或者将您的代码重构为仅 运行 实际单词的加密,例如使用 plaintext.split(' ') 获取列表要加密的单词,然后在列表中的每个项目上 运行ning encrypt/decrypt。

下面是如何在加密过程中忽略白色space。请注意,此实现假设通过“跳过白色 space”,您的意思是您 通常 仍会加密白色 space。对于 whitespace,密钥仍然前进,这不是完全正确的行为。

def encrypt(plain_text, key):
    ...
    for i in range(len(plaintextAsIntegers)):
        if plain_text[i] == ' ':
            encryptedtext += ' '
        else:
            encryptvalue = (plaintextAsIntegers[i] + keyAsIntegers[i % keyLength]) % 26 
            encyptedtext += chr(encryptvalue + 65)

解密应该是相反的过程。

...
if encryptedtext[i] == ' ':
    plain_text += ' ':
else:
...

不过这会使加密变弱,因为可以根据单词的长度猜测哪些单词可能是哪些单词。最好包括所有白色 spaces(包括制表符等)作为要加密的字符。