【问题标题】:Python3 - index out of range (Vigenere Cipher)Python3 - 索引超出范围(Vigenere Cipher)
【发布时间】:2016-05-13 03:17:54
【问题描述】:

我开始编写代码来执行 Vigenere 密码加密。首先,我想制作钥匙。密钥需要一遍又一遍地重复,直到它与要加密的消息的长度相匹配,所以我创建了一个可以为我执行此操作的函数:

def makekey(key, message):
    finalkey = []
    print(message) # to see if the key fits under the message correctly
    key = list(key)
    while len(finalkey) < len(message): # while the key is shorter than the message
        for i in range(0, len(key)): # iterate through characters in the key
            finalkey.append(key[i]) # append the characters in the processed key list
                if len(finalkey) > len(message): # if the final key is still bigger than the message
                    difference = len(finalkey) - len(message) # finds the difference between the two
                    del key[-difference] # removes the difference
    return ''.join(finalkey) # joins the final key into a string

print(makekey("LOVE", "Python")) # calling the function

输出应如下所示:

Python
LOVELO

但是程序只是给了我一个超出范围的索引错误,我不知道发生了什么!

错误信息:

Traceback (most recent call last):
  File "test.py", line 14, in <module>
    print(makekey("LOVE", "Python")) # calling the function
  File "test.py", line 8, in makekey
    finalkey.append(key[i]) # append the characters in the processed key list
IndexError: list index out of range

【问题讨论】:

  • 有一个更简单的方法使用cycle
  • itertools -> 循环。

标签: python loops vigenere


【解决方案1】:

您的代码不起作用的原因:

del key[-difference]

应该是:

del finalkey[-difference]

您在删除该元素后尝试访问 finalkey.append(key[i])(其中 i=3)行中的 key[3] 会得到一个 IndexError

为了好玩,这里有一个替代实现。

def make_key(key, message):
    """ Returns a string that repeats the `key` string until it's
        the length of the `message` string
    """
    if len(key) < len(message):  # only lengthen key if it's too short
        # In python, "abc" * 3 == "abcabcabc"
        # so what would we need to multiply our `key` by to get
        # it to be as long as `message`, or longer?
        # A guaranteed answer is: floor(len(message) / len(key)) + 1
        multiplier = (len(message) // len(key)) + 1
        key = key * multiplier
    # now we have a `key` that is at least as long as `message`
    # so return a slice of the key where the end of the slice == len(message)
    return key[:len(message)]

print(makekey("LOVE", "Python"))

打印:LOVELO

编辑 - 神秘的单线解决方案

如果你想让所有阅读你代码的人都对你翻白眼,你可以试试这个:

from itertools import islice, cycle
key = "LOVE"
message = "Python"
finalkey = ''.join(islice(cycle(key), len(message)))

cycle 函数接受一个iterable 对象——在我们的例子中是key 字符串——并在无限循环中重复它。因此,如果我们创建cycle("LOVE"),它将永远生成"L", "O", "V", "E", "L", "O", "V", "E", "L" ...

islice 函数允许我们对迭代器对象进行“切片”。在 Python 中,“切片”是表达式 new = old[0:3][0:3] 部分的术语——我们“切片”出原始的一个子集。由于我们不希望我们的字符串无限长 - 这不会很有用 - 我们只想获取我们创建的 cycle 的一部分:

islice(cycle(key), len(message)

这需要我们的迭代器 - cycle(key) - 并从索引 0 开始对它进行切片,并以索引 len(message) 结束。这将返回另一个迭代器——这一次,不是无限的。迭代器的内容现在是:"L", "O", "V", "E", "L", "O"

现在,我们只需要将 islice 拼接成一个完整的字符串:

''.join(islice...) == "LOVELO"

只是为了给你工具箱里的另一个工具!

【讨论】:

  • 等等,你的代码版本是如何工作的,你知道我的代码出了什么问题吗?
  • @user3124306 我已经完成了编辑我的回复以完全回答您的问题。我还对问题本身提交了一些建议的修改。
  • 谢谢!该死,我因为没有意识到自己做了什么而感到很愚蠢——我发誓我已经检查了三次代码......另外,当你说“floor(len(message)/len(key)”时,“floor”是什么意思? ) + 1'?
  • 当两个数字相除时,取结果的“下限”是将其四舍五入到最接近的最低整数(向上取整,术语为“上限”)。在 Python3 中,此操作符是 //(整数除法)。所以我想看看有多少次 whole 键将适合消息,并忽略小数。所以让我们说len(message) == 10len(key) == 3 - 10//3 == 3。但是,此时,如果我这样做 key * 3 我将只有 9 个字符 - 所以只需在结果中添加 1。 (10//3) + 1 == 4len(key*4) &gt; len(message) 保证 True
  • 非常感谢,迄今为止我在 stackoverflow 上得到的最佳答案和解释!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-07-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-11
相关资源
最近更新 更多