原子地替换多个字符

Replace multiple characters atomicaly

我正在使用频率分析解密替代密码(不是 Caesar/ROT),没有专门的工具。假设我想使用这个经过分析似乎足够好的密码字典:

key = {
'S':'E',
'Q':'A',
'J':'T',
'U':'O',
'B':'I',
'N':'N',
'C':'L',
'G':'R',
'D':'H',
'V':'S',
'Z':'D',
'W':'C',
'M':'U',
'Y':'M',
'T':'F',
'X':'P',
'K':'G',
'E':'W',
'L':'Y',
'A':'B',
'F':'V',
'I':'K',
'O':'X',
'H':'J',
'R':'Q',
'P':'Z'
}

我下面的代码有一个明显的问题:

 with open(filename) as f:
     out = f.read()
     for k in key:
         out = out.replace(k,key[k])
     print out

因为它一个接一个地替换每个字符,所以在算法完成之前,某个位置的字符会被替换多次,而不是一次。 (即:第一次迭代算法将用 E 替换所有 S,但随后到达字典中的 E 并替换 all Es 与 W)

Python有没有方便的方法一次性完成这个操作?还是我会被迫跟踪自己已经改变的位置?

对于Python3.x,你可以用str.maketrans() (or string.maketrans() for Python 2.x) and str.translate()这个-

In [27]: key = {
   ....: 'S':'E',
   ....: 'Q':'A',
   ....: 'J':'T',
   ....: 'U':'O',
   ....: 'B':'I',
   ....: 'N':'N',
   ....: 'C':'L',
   ....: 'G':'R',
   ....: 'D':'H',
   ....: 'V':'S',
   ....: 'Z':'D',
   ....: 'W':'C',
   ....: 'M':'U',
   ....: 'Y':'M',
   ....: 'T':'F',
   ....: 'X':'P',
   ....: 'K':'G',
   ....: 'E':'W',
   ....: 'L':'Y',
   ....: 'A':'B',
   ....: 'F':'V',
   ....: 'I':'K',
   ....: 'O':'X',
   ....: 'H':'J',
   ....: 'R':'Q',
   ....: 'P':'Z'
   ....: }

In [28]: t = str.maketrans(key)

In [29]: "ABCDEFGZYXW".translate(t)
Out[29]: 'BILHWVRDMPC'

对于Python 2.x,

>>> from string import maketrans
>>> t = maketrans(''.join(key.keys()) , ''.join(key.values()))
>>> "ABCDEFGZYXW".translate(t)
'BILHWVRDMPC'