2

我看过类似的主题,但没有找到与我想要达到的目标完全匹配的解决方案。

我有一个密文,需要根据文本中每个字母出现的频率进行简单的字母替换。我已经有一个函数来规范化文本(小写,没有非字母字符,没有,计数字母出现然后得到每个字母的相对频率。字母是字典中的键,频率是值。

我在单独的字典中也有 AZ 的预期字母频率(k=字母,v=频率),但我对接下来要做什么有点困惑。

我认为我需要做的是获取规范化的密文、预期的字母频率字典 [d1] 和密码字母频率字典 [d2] 并按如下方式迭代它们(部分伪代码):

for word in text:
    for item in word:
        for k,v in d2.items():
            if d2[v] == d1[v]:
                replace any instance of d2[k] with d1[k] in text
    decoded_text=open('decoded_text.txt', 'w')
    decoded_text.write(str('the decoded text')

在这里,我想获取文本并说“如果 d2 中的值与 d1 中的值匹配,则将 d2[k] 的任何实例替换为文本中的 d1[k]”。

我意识到我一定在那里犯了一些基本的 Python 逻辑错误(我在 Python 方面相对较新),但我在正确的轨道上吗?

提前致谢

更新:

感谢您提供所有有用的建议。我决定尝试 Karl Knechtel 的方法,并进行一些更改以适应我的代码。但是,我仍然遇到问题(完全在我的实施中)

我已经制作了一个解码功能来获取有问题的密文文件。这会调用之前创建的 count 函数,该函数返回一个字典(字母:频率为浮点数)。这意味着“制作大写版本”代码不起作用,因为 k 和 v 不是浮点数并且不能将 .upper 作为属性。所以,调用这个解码函数会返回密文字母频率,然后是密文本身,仍然是编码的。

def sorted_histogram(a_dict):
    return [x[1] for x in sorted(a_dict.items(), key=itemgetter(1))]

def decode(filename):
    text=open(filename).read()
    cipher=text.lower()

    cipher_dict=count(filename)

    english_histogram = sorted_histogram(english_dict)
    cipher_histogram = sorted_histogram(cipher_dict)

    mapping = dict(zip(english_histogram, cipher_histogram)

    translated = ''.join(
    mapping.get(c, c)
    for c in cipher
    )
    return translated
4

3 回答 3

0

首先,请注意频率不太可能为您提供完全匹配的信息,除非您的信息很长。因此,您可能需要进行一些手动调整才能获得确切的消息。但如果频率足够接近......

您可以获得两个字典(字母)的键,按它们的值(频率)排序:

letters_in_frequency_order = sorted(d1.keys(), key=lambda x: d1[x])

然后把它们变成字符串:

normal_alphabet = "".join(letters_in_frequency_order)

然后使用它们来翻译字符串:

import string
transtable = string.maketrans(cypher_alphabet, normal_alphabet)
cyphertext.translate(transtable)
于 2010-12-13T01:40:57.187 回答
0

您并不是真的想做您想做的事情,因为样本中字符的频率通常不会与参考数据中的确切频率分布相匹配。您真正想做的是找到最常见的字符并将其替换为“e”,然后将其替换为“t”,依此类推。

所以我们要做的是:

  1. (我假设你已经可以做这部分)在密文中构造一个实际字母频率的字典。

  2. 我们定义了一个函数,它接受一个 {letter: frequency} 字典并按频率顺序生成一个字母列表。

  3. 我们在参考文献(即,现在我们有一个英语中最常见字母的有序列表)和样本中(类似地)得到字母,按频率顺序排列。

  4. 假设样本中最常见的字母对应于英语中最常见的字母,依此类推:我们创建一个新字典,将第一个列表中的字母映射到第二个列表中的字母。(我们也可以创建一个翻译表来与 . 一起使用str.translate。)我们将制作同一个字典的大写和小写版本(我假设您的原始字典只有小写)并将它们合并在一起。

  5. 我们使用此映射来翻译密文,而忽略其他字符(空格、标点符号等)。

因此:

# 2.
import operator
def sorted_histogram(a_dict):
  return [
    x[1] # the value
    for x in sorted(a_dict.items(), key=operator.itemgetter(1))
    # of each dict item, sorted by value (i.e. the [1] element of each item).
  ]

# 3.
english_histogram = sorted_histogram(english_dict)
cipher_histogram = sorted_histogram(cipher_dict)

# 4.
# Make the lowercase version
mapping = dict(zip(english_histogram, cipher_histogram))
# Make the uppercase version, and merge it in at the same time.
mapping.update(dict(
  (k.upper(), v.upper()) for (k, v) in zip(english_histogram, cipher_histogram)
))

# 5.
translated = ''.join( # make this list of characters, and string them together:
  mapping.get(c, c) # the mapped result, if possible; otherwise the original
  for c in cipher
)

# 6. Do whatever you want with 'translated' - write to file, etc.
于 2010-12-13T01:41:42.990 回答
0
#!/usr/bin/env python
from operator import itemgetter
import string

def frequency(text):
    d = {}
    for letter in text:
        try:
            d[letter] += 1
        except:
            d[letter] = 1
    return d

def alphabet():
    for alpha in string.letters: yield alpha

def cipher(text):
    expected = frequency(text)
    flist = sorted(expected.iteritems(), key=itemgetter(1), reverse=True)
    alphabet_generator = alphabet()
    for char, freq in flist:
        text = text.replace(char, alphabet_generator.next())
    return (text, expected)

def decipher(text, expected):
    nal = [ x[0] for x in sorted(expected.iteritems(), key=itemgetter(1), \
            reverse=True) ]
    normal_alphabet = ''.join(nal)
    transtable = string.maketrans(string.letters[:len(normal_alphabet)], \
                                  normal_alphabet)
    return text.translate(transtable)

用法:

if __name__ == '__main__':
    s = "SUMMERTIMEANDTHELIVINGISEASYFISHESJUMPING"
    ciphered, expected = cipher(s)
    print s
    print ciphered
    print decipher(ciphered, expected)

# SUMMERTIMEANDTHELIVINGISEASYFISHESJUMPING
# ciddbpjadbfekjhbnaqaegacbfcrlachbcmidoaeg
# SUMMERTIMEANDTHELIVINGISEASYFISHESJUMPING
于 2010-12-13T01:59:37.447 回答