【问题标题】:Vigenere Cipher Key not working as expectedVigenere Cipher Key 未按预期工作
【发布时间】:2019-08-23 19:49:15
【问题描述】:

我已经构建了一个运行良好的 Vigenere 密码函数,除了它没有通过我需要通过的编码测试这一事实。

这是因为我使用的是序数值,而我认为测试期望我使用一个函数来旋转字符串字母。

我已经解决了处理非字母字符的问题,并让它同时处理大写和小写字符。但是,如果密钥有大写或小写字符的任何变化,即密钥是小写但纯文本是大写,它似乎会崩溃。

def encrypt(text, key):
    cipher_text = []
    key = list(key) 
    if len(text) == len(key): 
        return(key) 
    else: 
        for i in range(len(text) - 
                       len(key)): 
            key.append(key[i % len(key)]) 
    for i in range(len(text)): 
        a = text[i]
        if a.isalpha() and a.islower():
            x = ((ord(text[i]) + ord(key[i])-97) % 26 + 97)
            cipher_text.append(chr(x))
        elif a.isalpha() and a.isupper():
            x = ((ord(text[i]) + ord(key[i])-65) % 26 + 65)
            cipher_text.append(chr(x))
        else: 
            cipher_text.append(a) 

    return("" . join(cipher_text)) 


def main():
    mess = input(str("What is message?"))
    key = input("What is key?")
    print(encrypt(mess, key))

if __name__ == '__main__':
    main()

对于 vigenere.encrypt('BaRFoo', 'BaZ')

    You should have returned this:         
        'CaQGon'                           

    But you actually returned this:        
        'PtDTha'

【问题讨论】:

  • 如果我使用全部大写和全部小写,我会得到不同的答案。这似乎表明您没有同时使用大写和小写。
  • 这个短程序中有很多错误.. 1. 如果密钥长度等于源长度,它什么也不做,而是返回密钥。 2. 你从 key[i] 中减去 65 或 97,这取决于 text[i] 是低还是高。让它依赖于 key[i] 怎么样? 3. 你不能从 text[i] 中减去 65 / 97,但你应该这样做。 4. return 不是函数。不需要括号。

标签: python vigenere


【解决方案1】:

从您的单个示例看来,密钥不区分大小写:

def encrypt_letter(c, k):
  if c.isupper():
    base = ord('A')
  else:
    base = ord('a')

  return chr((ord(c) - base + ord(k) - ord('a')) % 26 + base)

def encrypt(text, key):
    key = key.lower()

    return "".join([encrypt_letter(text[i], key[i % len(key)]) for i in range(len(text))])

def main():
    print(encrypt('BaRFoo', 'BaZ'))

if __name__ == '__main__':
    main()

【讨论】:

    【解决方案2】:

    首先,我不会用 python 编程,所以请原谅我的表格。然而,我在在线编译器中测试了所有内容。

    在我回答你的问题之前,我不确定这部分:

        if len(text) == len(key): 
            return(key) 
        else: 
            for i in range(len(text) - 
                           len(key)): 
                key.append(key[i % len(key)]) 
    

    我将其读作“如果密钥与明文具有相同的长度,则密钥就是密文”,这显然不是真的,除非密钥是“aaaaaaaaaa ...”。我希望是这样的:

        if len(text) > len(key): 
            for i in range(len(text) - 
                           len(key)): 
                key.append(key[i % len(key)])
    #   else:
    #       I don't care - the key is long enough
    

    从 Kfir Dadosh 的回答中,我还要指出,您实际上并不需要这一步,不妨直接访问密钥为 key[i % len(key)]

    至于您所指的问题。您只需检查明文(消息)是小写还是大写并根据那个。

            if a.isalpha() and a.islower():
                x = ((ord(text[i]) + ord(key[i])-97) % 26 + 97)
    Here you take raw      ^                ^
    ascii value instead of |                |
    normalized (0-25) number                |
                                            |
    Here you normalize the key according to the
    message case
    

    以下是一些严重的剧透,所以如果你理解并想自己解决问题,那么请停止阅读这里。


    我建议将规范化和加密步骤分开,以避免混淆。让我们先去掉特殊字符而不是最后,因为这很容易做到,我们只需要担心字母:

            if not (text[i].isalpha()):
                cipher_text.append(text[i]) 
                continue; # done with this symbol - skip to the next one
    

    然后在内置方法的帮助下规范化字母。让我们使用变量 p 表示明文,k 表示密钥,c 表示密文(稍后):

            p = ord(text[i].lower()) - ord('a') # converts to lowercase, then to number
            k = ord(key[i].lower()) - ord('a')  # both key AND plaintext
    

    我使用 ord('a') 而不是 65,因为我已经习惯了并且发现它更清晰,但这是一个偏好和语言传统的问题(我不习惯)。

    然后是加密步骤:

            c = (p + k) % 26;
    

    现在恢复大写。我们在变量 p 和 k 中销毁了它,但我们仍然有它们的源数组 text[] 具有完整的值。我们可以使用它来恢复大写(假设应该从明文继承大小写):

            if (text[i].islower()):
                cipher_text.append(chr(c + ord('a')))
            elif (text[i].isupper()):
                cipher_text.append(chr(c + ord('A')))
    

    这样就完成了主循环。随意修改它以使其更符合 python。

        for i in range(len(text)):
            if not (text[i].isalpha()):
                cipher_text.append(text[i]) 
                continue;
    
            p = ord(text[i].lower()) - ord('a')
            k = ord(key[i].lower()) - ord('a')
            # k = ord(key[i % len(key)].lower()) - ord('a')
            # if you skipped the key lengthening process
    
            c = (p + k) % 26;
    
            if (text[i].islower()):
                cipher_text.append(chr(c + ord('a')))
            elif (text[i].isupper()):
                cipher_text.append(chr(c + ord('A')))
            else:
                # not sure if this can happen in python, but if it does, we're probably
                # in trouble
                # otherwise it might as well be merged with the elif above
    
        return("" . join(cipher_text)) 
    

    【讨论】:

    • 在 veprolet 和 @Kfir Dadosh 之间,我认为答案就在这里。 Kfir Dadosh 问题是特殊字符和 veprolet 我认为 python 上下文只是稍微偏离了。我会继续玩它,让你知道会发生什么。
    • @ChipWoodson 请注意,Kfir 的回答将代码很好地重组为函数,我避免这样做只是为了与您的代码保持更多相似性,因为我觉得函数足够短。他还跳过了密钥延长部分,直接以key[i % len(key)] 访问密钥,这样可以节省大量内存,尽管您的方法也可以。我将其编辑为我的答案。随意进一步编辑我的答案以符合 python 上下文,因为正如我所说,我对此一无所知。
    猜你喜欢
    • 1970-01-01
    • 2016-03-02
    • 2014-12-18
    • 1970-01-01
    • 2021-06-04
    • 2022-01-24
    • 2015-05-11
    • 2020-05-15
    • 2014-10-31
    相关资源
    最近更新 更多