Decipher( S)将被赋予一个移位了一定数量的英文文本字符串。然后,decipher应该尽其所能地返回原始英语字符串,这将是输入S的一些旋转(可能是0)。这意味着我必须尝试每种可能的解码并估计它们的英语程度。
我的方法是使用字母频率:
def letProb( c ):
""" if c is an alphabetic character,
we return its monogram probability (for english),
otherwise we return 1.0 We ignore capitalization.
Adapted from
http://www.math.cornell.edu/~mec/2003-2004/cryptography/subs/frequencies.html
"""
if c == 'e' or c == 'E': return 0.1202
if c == 't' or c == 'T': return 0.0910
if c == 'a' or c == 'A': return 0.0812
if c == 'o' or c == 'O': return 0.0768
if c == 'i' or c == 'I': return 0.0731
if c == 'n' or c == 'N': return 0.0695
if c == 's' or c == 'S': return 0.0628
if c == 'r' or c == 'R': return 0.0602
if c == 'h' or c == 'H': return 0.0592
if c == 'd' or c == 'D': return 0.0432
if c == 'l' or c == 'L': return 0.0398
if c == 'u' or c == 'U': return 0.0288
if c == 'c' or c == 'C': return 0.0271
if c == 'm' or c == 'M': return 0.0261
if c == 'f' or c == 'F': return 0.0230
if c == 'y' or c == 'Y': return 0.0211
if c == 'w' or c == 'W': return 0.0209
if c == 'g' or c == 'G': return 0.0203
if c == 'p' or c == 'P': return 0.0182
if c == 'b' or c == 'B': return 0.0149
if c == 'v' or c == 'V': return 0.0111
if c == 'k' or c == 'K': return 0.0069
if c == 'x' or c == 'X': return 0.0017
if c == 'q' or c == 'Q': return 0.0011
if c == 'j' or c == 'J': return 0.0010
if c == 'z' or c == 'Z': return 0.0007
return 1.0
我还使用了这个公式:
def list_to_str( L ):
""" L must be a list of characters; then,
this returns a single string from them
"""
if len(L) == 0: return ''
return L[0] + list_to_str( L[1:] )
还有这个:
def rot(c, n):
""" rot rotates c, a single character forward by n spots in the
alphabet
input: a single character
input: a non-negative integer n between 0 and 25
output: c forward by n spots in the alphabet
"""
if 'a' <= c <= 'z':
neword = ord(c) +n
if neword > ord('z'):
neword = neword - 26
elif 'A' <= c <= 'Z':
neword = ord(c) + n
if neword > ord('Z'):
neword = neword - 26
else:
neword = ord(c)
return chr(neword)
最后是这个:
def decipher( S ):
"""
"""
L = [[rot(c, n) for c in S] for n in range(26)]
LoL = [[sum(letProb(c)) for letter in encoding] for encoding in L ]
L = max(LoL)
return list_to_str(L)
前两个公式是好的,但在最后的公式中有一些错误,在句子中肯定是错误的:
LoL = [[sum(letProb(c)) for letter in encoding] for encoding in L ]
TypeError:“float”对象不可迭代
发布于 2015-10-04 19:03:38
您正在尝试sum( letProb (c)),其中letProb返回一个浮点数,而sum需要一个迭代器、一个列表或一个生成器,比方说。试试这样的东西。
LoL = [[sum(letProb(c) for letter in encoding)] for encoding in L ]
我也认为c可能应该是letter,但我不认为,如果你发布完整的代码,包括rot函数,也许我可以更好地帮助你。
发布于 2015-10-04 19:43:00
您可能会发现以下内容很有用。您可以使用某种形式的查找来获取字母概率。如果使用字典,则可以使用get
为非A到Z字符提供默认概率1.0
。
其次,Python的string
模块有一个make_trans
函数,可以与translate
一起使用来执行旋转。
import string
letter_probs = {
'e' : 0.1202, 't' : 0.0910, 'a' : 0.0812, 'o' : 0.0768,
'i' : 0.0731, 'n' : 0.0695, 's' : 0.0628, 'r' : 0.0602,
'h' : 0.0592, 'd' : 0.0432, 'l' : 0.0398, 'u' : 0.0288,
'c' : 0.0271, 'm' : 0.0261, 'f' : 0.0230, 'y' : 0.0211,
'w' : 0.0209, 'g' : 0.0203, 'p' : 0.0182, 'b' : 0.0149,
'v' : 0.0111, 'k' : 0.0069, 'x' : 0.0017, 'q' : 0.0011,
'j' : 0.0010, 'z' : 0.0007}
def rotate(text, rotate_by):
s_from = string.ascii_lowercase + string.ascii_uppercase
s_to = string.ascii_lowercase[rotate_by:] + string.ascii_lowercase[:rotate_by] + \
string.ascii_uppercase[rotate_by:] + string.ascii_uppercase[:rotate_by]
cypher_table = string.maketrans(s_from, s_to)
return text.translate(cypher_table)
def sum_probs(text):
global letter_probs
return sum(letter_probs.get(c.lower(), 1.0) for c in text)
def decipher(text):
probabilities = []
for r in range(26):
rotated = rotate(text, r)
probabilities.append((sum_probs(rotated), rotated, r))
return sorted(probabilities)
for probability, decoded_text, rotate_value in decipher("Mjqqt Btwqi"):
print '{:2.2f} {:2} "{}"'.format(probability, rotate_value, decoded_text)
这将以概率顺序显示所有可能性:
1.17 19 "Fcjjm Umpjb"
1.20 16 "Czggj Rjmgy"
1.22 9 "Vszzc Kcfzr"
1.26 20 "Gdkkn Vnqkc"
1.28 13 "Zwddg Ogjdv"
1.29 4 "Qnuux Fxaum"
1.29 15 "Byffi Qilfx"
1.30 8 "Uryyb Jbeyq"
1.31 6 "Spwwz Hzcwo"
1.32 5 "Rovvy Gybvn"
1.32 0 "Mjqqt Btwqi"
1.33 12 "Yvccf Nficu"
1.34 1 "Nkrru Cuxrj"
1.37 23 "Jgnnq Yqtnf"
1.39 7 "Tqxxa Iadxp"
1.40 22 "Ifmmp Xpsme"
1.40 2 "Olssv Dvysk"
1.44 25 "Lipps Asvph"
1.45 17 "Dahhk Sknhz"
1.47 24 "Khoor Zruog"
1.49 11 "Xubbe Mehbt"
1.52 3 "Pmttw Ewztl"
1.56 10 "Wtaad Ldgas"
1.58 21 "Hello World"
1.61 14 "Axeeh Phkew"
1.68 18 "Ebiil Tloia"
正如你所看到的,答案在底部附近。
https://stackoverflow.com/questions/32936963
复制