解密我的密码:Python Wizardry

时间:2014-10-03 01:16:55

标签: python

我试图编写一个函数decipher(s),该函数采用加密字符串旋转的字符串,然后返回原始的英文字符串。一个例子:

>>> decipher('Bzdrzq bhogdq? H oqdedq Bzdrzq rzkzc.')
'Caesar ciaapher? I preferr Caesaar saladd.'

它应该只接受一个字符串作为输入。以下是我写入加密的所有功能。我想知道如何使用rot函数对letter_prob中的所有可能选项进行评分,然后返回包含所有max(最可能)字母出现的字符串。

def decipher(s):
    lc= [rot for c in s] 
    options = [lc for n in range(26)]
    scored_options = [[letter_prob(c),c] for c in options]
    best_option = max(scored_options)
    return best_option[1]      

如何重写decipher以便它返回一个包含所有最可能字符的字符串?

2 个答案:

答案 0 :(得分:0)

我没有尝试过,但这样的事情应该有效:

def decipher(s):
    options = [[rot(c, n) for c in s] for n in range(26)]
    best_option = max(options, key=lambda x: sum(map(letter_prob, x)))
    return ''.join(best_option)

options将是每个组合的列表,如下所示:

[['B', 'z', 'd', 'r', 'z', 'q', ...], ['C', 'a', 'e', 's', 'a', 'r', ...], ...]

然后我们使用maxkey参数来获得具有最高字母概率总和的选项。 ''.join()将字符列表转换回字符串。


def decipher(s):
    options = [[rot(c, n) for c in s] for n in range(26)]
    scored_options = [[sum(map(letter_prob, x)), x] for x in options]
    best_option = max(options)
    return ''.join(best_option)

答案 1 :(得分:0)

我使用NumPy制作了代码的矢量化版本。我发现这一点更清楚了(虽然如果你之前没有看过NumPy,它起初会有点异国情调),对于长字符串它会更快:

import numpy as np

_a = ord('a')
_z = ord('z')
_A = ord('A')
_Z = ord('Z')

def encipher(s, n):
    arr = np.fromstring(s, np.uint8)
    rawcipher(arr, n)
    return arr.tostring()

def rawcipher(arr, n):
    lower = (arr >= _a) & (arr <= _z)
    upper = (arr >= _A) & (arr <= _Z)
    arr[lower | upper] += n
    arr[lower & (arr > _z)] -= 26
    arr[upper & (arr > _Z)] -= 26

letters = np.ones(128, dtype=np.float32)
letters[ord(' ')] = 0.1904
letters[ord('e')] = 0.1017
letters[ord('t')] = 0.0737
letters[ord('a')] = 0.0661
letters[ord('o')] = 0.0610
letters[ord('i')] = 0.0562
letters[ord('n')] = 0.0557
letters[ord('h')] = 0.0542
letters[ord('s')] = 0.0508
letters[ord('r')] = 0.0458
letters[ord('d')] = 0.0369
letters[ord('l')] = 0.0325
letters[ord('u')] = 0.0228
letters[ord('m')] = 0.0205
letters[ord('c')] = 0.0192
letters[ord('w')] = 0.0190
letters[ord('f')] = 0.0175
letters[ord('y')] = 0.0165
letters[ord('g')] = 0.0161
letters[ord('p')] = 0.0131
letters[ord('b')] = 0.0115
letters[ord('v')] = 0.0088
letters[ord('k')] = 0.0066
letters[ord('x')] = 0.0014
letters[ord('j')] = 0.0008
letters[ord('q')] = 0.0008
letters[ord('z')] = 0.0005
letters[_A:_Z+1] = letters[_a:_z+1]

def score(arr):
    return letters[arr].sum()

def decipher(s):
    arr = np.fromstring(s, np.uint8)
    bestStr = None
    bestScore = 0
    for n in range(0, 26):
        rawcipher(arr, 1)
        thisScore = score(arr)
        if thisScore > bestScore:
            bestScore = thisScore
            bestStr = arr.tostring()

    return bestStr

请注意,Python中唯一的循环是在尝试所有可能的解密距离时从0到26。

我计时了,我的矢量化加密()需要3.6秒才能处理122 MB,而原始版本需要永久(我在40分钟后放弃了)。