【问题标题】:Python: Inconsistent results replacing letters in a list of charactersPython:替换字符列表中的字母的结果不一致
【发布时间】:2013-07-02 02:57:27
【问题描述】:

我正在用 python 编写一个 ROT13 脚本。它通过将字符串分成单个字符列表并使用 for 循环来工作,遍历每个字母并检查它是否需要被字典翻译。

问题在于它并不总是替换列表中的字母。我不知道为什么,但只有一些字符串有效。

代码如下:

import string
def rot13(m):
    Data for ROT13 conversion                                                        
    alphabet = list("abcdefghijklmnopqrstuvwxyz")
    mapping = {}
    for letter in alphabet:
        mapping[letter] = alphabet[(alphabet.index(letter) + 13)%26]
    for letter in alphabet:
        mapping[letter.upper()] = alphabet[(alphabet.index(letter) +13)%26].upper()
    # Create a list of the characters in order                                         
    characters = list(m)
    # Go through each character in the list...                                         
    for character in characters:
        # Check if that character is one that needs to be changed                      
        if character in mapping:
            # Test to chcek if it is finding characters correctly (it is)              
            print "%s to %s" % (character, mapping[character])
            # replace the character with a new one (works inconsistently)              
            characters[characters.index(character)] = mapping[character]
        #Bring it all together                                                         
        result = string.join(characters, "");
    return result

print rot13("ABCDEF") # Returns NOPQRS                                                 
print rot13("ABCDEFGHIJKLMNOPQRSTUVWXYZ") # Returns original string 

第一个测试包含部分大写字母,结果与预期一样。但是,完整的字母表在通过我的 ROT13 函数时只返回原始字符串。

我确信问题出在第 20 行,characters[characters.index(character)] = mapping[character]

这一行应该将列表中的字母替换为开头构建的 rot13 字典中的对应字母,但并不总是这样做。

在它之前有一行打印它正在测试的字符以及它应该根据字典更改为什么,并且总是有效的。但如果是这样,那为什么不是这一行呢?

【问题讨论】:

  • 你应该使用"".join(characters)而不是string.join(characters, "")(这是你必须为Python1做的方式)
  • 为什么您要导入string 模块? only 应该使用的东西是常量,而不是使用常量,而是使用 deprecated 函数。将alphabet = ... 行替换为alphabet = list(string.lowercase)。顺便说一句:为什么您要将它们转换为lists?您可以遍历字符串中的字符。

标签: python list for-loop rot13


【解决方案1】:

characters.index(character) 查找与该字符相等的第一个元素的索引。

for character in characters 循环 13 次迭代后,characters 看起来像 list("NOPQRSTUVWXYZNOPQRSTUVWXYZ")character 将是 "N" 所以 characters.index(character) 将是 0 所以你最终会得到 characters[0] = mapping["N"] characters[13] = mapping["N"]。当然是mapping["N"] == "A"

试试:

for index, character in enumerate(characters):
    # Check if that character is one that needs to be changed                      
    if character in mapping:
        # Test to chcek if it is finding characters correctly (it is)              
        print "%s to %s" % (character, mapping[character])
        # replace the character with a new one (works inconsistently)              
        characters[index] = mapping[character]
    #Bring it all together                                                         
    result = string.join(characters, "");

【讨论】:

    【解决方案2】:

    索引查找列表中的第一个匹配字符。前 13 次迭代将字母表变成 n-z 重复两次。然后第二个 13 次迭代将其撤消 - 第 14 次迭代得到一个 n 作为其字符,计算出它需要一个 a,然后调用 index ('n') 并得到 0 - 第一个 'n' 在字符中的新索引。它将第一个 'n' 替换为 'a' 并继续前进。

    有很多更好的方法可以编写此代码,但对于初学者,您应该阅读有关 enumerate 内置函数的信息。自己跟踪列表位置而不是每次都搜索至少可以解决这个问题。

    【讨论】:

    • 感谢您尝试调试它。
    【解决方案3】:

    试试这个版本的大小。应该更容易调试。

    def translate_char(c):
        """Translate a single character using a dictionary"""
        translation_table = {
            'a':'n',
            'b':'o',
            'c':'p',
            'd':'q',
            'e':'r',
            'f':'s',
            'g':'t',
            'h':'u',
            'i':'v',
            'j':'w',
            'k':'x',
            'l':'y',
            'm':'z',
            'n':'a',
            'o':'b',
            'p':'c',
            'q':'d',
            'r':'e',
            's':'f',
            't':'g',
            'u':'h',
            'v':'i',
            'w':'j',
            'x':'k',
            'y':'l',
            'z':'m',
            'A':'N',
            'B':'O',
            'C':'P',
            'D':'Q',
            'E':'R',
            'F':'S',
            'G':'T',
            'H':'U',
            'I':'V',
            'J':'W',
            'K':'X',
            'L':'Y',
            'M':'Z',
            'N':'A',
            'O':'B',
            'P':'C',
            'Q':'D',
            'R':'E',
            'S':'F',
            'T':'G',
            'U':'H',
            'V':'I',
            'W':'J',
            'X':'K',
            'Y':'L',
            'Z':'M'}
        if c in translation_table.keys():
            return translation_table[c]
        else:
            return c    
    
    def rot13(plaintext):
        """Translate a complete string"""
        ciphertext = ""
        for c in plaintext: 
            ciphertext = ciphertext + translate_char(c)
        return ciphertext
    
    if __name__ == "__main__":
    
        plaintext = "The quick brown fox jumped over the lazy black dog."
        print rot13(plaintext)
    

    【讨论】:

      【解决方案4】:

      我使用maketrans表单字符串模块实现如下。

      from string import maketrans
      def rot_it(text):
            intab = "abcdefghijklmnopqrstuvwxyz"
            in_rot = intab + intab.upper()
            outtab = "nopqrstuvwxyzabcdefghijklm"
            out_rot = outtab + outtab.upper()
            trans = maketrans(in_rot, out_rot)
            rot13 = text.translate(trans)
            return rot13
      

      【讨论】:

      • intab = string.lowercase; outtab = intab[13:] + intab[:13]
      最近更新 更多