简体   繁体   English

Python:用不一致的结果替换字符列表中的字母

[英]Python: Inconsistent results replacing letters in a list of characters

I am writing a ROT13 script in python. 我正在用python编写ROT13脚本。 It works by separating the string into a list of single characters and using a for-loop, goes through each letter and checks if it needs to be translated by a dictionary. 它通过将字符串分成单个字符列表并使用for循环进行工作,遍历每个字母并检查是否需要字典翻译。

The problem is it doesn't always replace the letter in the list. 问题是它并不总是替换列表中的字母。 I can't figure out why, but only some strings work. 我不知道为什么,但是只有一些字符串有效。

Here is the code: 这是代码:

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 

The first test, with part of the uppercase alphabet, comes out just as expected. 包含部分大写字母的第一个测试按预期进行。 However, the full alphabet just returns the original string when put through my ROT13 function. 但是,通过我的ROT13函数输入时,完整的字母只会返回原始字符串。

I am convinced the problem is with line 20, characters[characters.index(character)] = mapping[character] . 我确信问题出在第20行, characters[characters.index(character)] = mapping[character]

This line is supposed to replace the letter in the list with the corresponding one from the rot13 dictionary constructed in the beginning, but it doesn't always do that. 该行应该用开始时构建的rot13词典中的相应字母替换列表中的字母,但并不总是这样做。

I have a line right before that prints the character it is testing and what it should be changed to based off the dictionary, and that always works. 我在一行之前打印了正在测试的字符,并根据字典将其更改为什么,并且该行始终有效。 But if that does, then why not this other line? 但是,如果是这样,那为什么不选择另一行呢?

characters.index(character) finds the index of the first element equal to that character. characters.index(character)查找等于该字符的第一个元素的索引。

After 13 iterations of your for character in characters loop characters will look like list("NOPQRSTUVWXYZNOPQRSTUVWXYZ") and character will be "N" so characters.index(character) will be 0 so you end up with characters[0] = mapping["N"] when you expect characters[13] = mapping["N"] . 之后你的13次迭代for character in characters循环characters的样子list("NOPQRSTUVWXYZNOPQRSTUVWXYZ")character将是"N"所以characters.index(character)将是0 ,所以你最终与characters[0] = mapping["N"]当您期望characters[13] = mapping["N"] Of course mapping["N"] == "A" . 当然mapping["N"] == "A"

Try: 尝试:

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, "");

Index finds the first matching character in the list. 索引查找列表中的第一个匹配字符。 The first 13 iterations turn the alphabet into nz repeated twice. 前13次迭代将字母重复两次变成nz。 Then the second 13 iterations undo it - the 14th iteration gets an n as its character, calculates that it needs an a instead, then calls index ('n') and gets 0 - the new index of the first 'n' in characters. 然后,第二十三次迭代将其撤消-第十四次迭代将n作为其字符,计算它需要一个a,然后调用索引('n')并获得0-字符中第一个'n'的新索引。 It replaces that first 'n' with an 'a' and moves on. 它用“ a”代替第一个“ n”并继续前进。

There are a lot of better ways you could write this, but just for starters you should read about the enumerate built in function. 有很多更好的方法可以编写此代码,但是对于初学者来说,您应该阅读有关内置函数的枚举。 Keeping track of the list position yourself rather than searching each time will at least get you past this problem. 自己跟踪列表位置,而不是每次都搜索,至少可以使您摆脱这个问题。

Try this version on for size. 试穿此版本以获取尺寸。 Should be a bit easier to debug. 应该更容易调试。

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)

I implemented as follows using maketrans form string module. 我使用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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM