将字符串中所有字符的所有出现替换为另一个字符,而不会相互干扰

时间:2015-11-06 13:46:16

标签: python algorithm encryption

我开始从一本书中学习一些加密技术,现在我有一项练习要求我从字符串中找出每个字符的频率:

这样的事情:

import collections

my_coded_string = """NTCGPDOPANFLHJINTOOFITOVJHJCTMMHIHEMTCPFDWTSOFSHTOGFWTE
TTJJTBTOOFSZOVEOCHCVCHPJHOCGTOHNQMTOCNTCGPDCGFCSTQMFBTO
FBGFSFBCTSHJCGTQMFHJCTYCXHCGFAHYTDDHAATSTJCBGFSFBCTSHJC
GTBHQGTSCTYCCGHONTCGPDQSTOTSWTOCGTMTCCTSASTRVTJBZHJCGTQ
MFHJCTYCFJDOPPJTBFJOTFSBGAPSCGTQMFHJCTYCASPNFIHWTJBHQGT
SCTYCEZBPNQFSHJICGTASTRVTJBZPATFBGMTCCTSFIFHJOCCGTLJPXJ
BPNNPJASTRVTJBZHJCGTVJDTSMZHJIMFJIVFIT"""

letters = collections.defaultdict(float)
for letter in my_coded_string:
    letters[letter] += 1

d_descending = OrderedDict(sorted(letters.items(), key=lambda x: x[-1], reverse=True))
print d_descending

这将返回类型float的字典,其中包含所有键及其频率(按降序排列)。到目前为止一切都那么好,没什么可怕的。

输出:

([
    ('T', 57.0), ('C', 40.0), ('J', 29.0), ('F', 27.0), ('H', 26.0), ('S', 23.0), ('G', 22.0), ('O', 20.0), ('B', 16.0), 
    ('P', 15.0), ('M', 12.0), ('A', 10.0), ('N', 10.0), ('I', 9.0), ('Q', 9.0), ('D', 8.0), ('V', 8.0), ('Y', 6.0), 
    ('Z', 6.0), ('E', 4.0), ('W', 4.0), ('R', 3.0), ('L', 2.0), ('X', 2.0)
])

现在,他们说为了解码这个字符串,我必须将这些频率与它们提供的频率进行比较,这似乎是英语中每个字符的预期频率。

enter image description here

现在,我遇到的问题是:我怎样才能更换最常出现的字母T的所有出现,字母E是第一个常用的英文字母,然后是{{ 1}}与C等等?

在某些时候,当我用T替换T时,我会有57 E秒,但我还会剩下E秒。有什么想法吗?

1 个答案:

答案 0 :(得分:1)

如果您还为预期英语的映射创建OrderedDict 语言(递减顺序),您将能够创建一个 第二个dict,可用于将my_coded_string翻译成一个 迭代。

让我们说预期的英语映射称为freqs

translate_table = dict(zip(d_descending, freqs))
my_string = ''.join([translate_table[c] for c in my_coded_string])

假设您还想处理换行符\n),这里有一个完整的代码:

import collections
import itertools

freqs = collections.OrderedDict([
    ('e', 12.702), ('t', 9.056), ('a', 8.167), ('o', 7.507),
    ('i', 6.749), ('n', 6.749), ('s', 6.327), ('h', 6.094),
    ('r', 5.987), ('d', 4.253), ('l', 4.052), ('c', 2.782),
    ('u', 2.758), ('m', 2.406), ('w', 2.360), ('f', 2.228),
    ('g', 2.015), ('y', 1.974), ('p', 1.929), ('b', 1.492),
    ('v', 0.978), ('k', 0.772), ('j', 0.153), ('x', 0.150),
    ('q', 0.095), ('z', 0.074)])

my_coded_string = """NTCGPDOPANFLHJINTOOFITOVJHJCTMMHIHEMTCPFDWTSOFSHTOGFWTE
TTJJTBTOOFSZOVEOCHCVCHPJHOCGTOHNQMTOCNTCGPDCGFCSTQMFBTO
FBGFSFBCTSHJCGTQMFHJCTYCXHCGFAHYTDDHAATSTJCBGFSFBCTSHJC
GTBHQGTSCTYCCGHONTCGPDQSTOTSWTOCGTMTCCTSASTRVTJBZHJCGTQ
MFHJCTYCFJDOPPJTBFJOTFSBGAPSCGTQMFHJCTYCASPNFIHWTJBHQGT
SCTYCEZBPNQFSHJICGTASTRVTJBZPATFBGMTCCTSFIFHJOCCGTLJPXJ
BPNNPJASTRVTJBZHJCGTVJDTSMZHJIMFJIVFIT"""

def translate(coded):
    coded_lines = coded.split('\n')
    letters = collections.defaultdict(float)
    for letter in itertools.chain(*coded_lines):
        letters[letter] += 1

    mapping = dict(zip(
        (i[0] for i in sorted(letters.items(),
                              key=lambda x: x[-1], reverse=True)),
        freqs.keys()))

    return '\n'.join(''.join(mapping[letter] for letter in line)
                     for line in coded_lines)

print(translate(my_coded_string))