Зашифрованный текст Letter Freq Substitution: сравнение двух разных словарей по значению и изменение текста - PullRequest
2 голосов
/ 13 декабря 2010

Я смотрел на подобные темы, но ни одно решение, которое я не могу найти, в точности совпадает с тем, что я пытаюсь достичь.

У меня есть зашифрованный текст, который должен пройти простую замену букв на основена частоте появления каждой буквы в тексте.У меня уже есть функция для нормализации текста (строчные буквы, без буквенных символов, нет, количество встречаемых букв и затем получение относительной частоты каждой буквы. Буква - это ключ в словаре, а частота - это значение.

У меня также есть ожидаемые буквенные частоты для AZ в отдельном словаре (k = буква, v = частота), но я немного озадачен тем, что делать дальше.

Что я думаюМне нужно сделать, это взять нормализованный зашифрованный текст, ожидаемую букву freq dict [d1] и зашифрованную букву freq dict [d2] и перебрать их следующим образом (часть psuedocode):

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), но я на правильном пути?

Заранее спасибо

Обновление:

Спасибоза все полезные предложения. Я решилЯ решил попробовать метод Карла Кнехта с некоторыми изменениями, чтобы вписаться в мой код.Однако, у меня все еще есть проблемы (полностью в моей реализации)

Я сделал функцию декодирования, чтобы взять рассматриваемый файл зашифрованного текста.Это вызывает ранее созданную функцию подсчета, которая возвращает словарь (буква: частота в виде числа с плавающей запятой).Это означало, что код «make uppercase version» не будет работать, так как k и v не являются float и не могут принимать .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

Ответы [ 3 ]

0 голосов
/ 13 декабря 2010

Вы на самом деле не хотите делать то, о чем вы думаете, потому что частоты символов в выборке, как правило, не будут соответствовать точному распределению частот в справочных данных .Что вы действительно пытаетесь сделать, так это найти самый распространенный символ и заменить его на 'e', ​​следующий наиболее часто и заменить его на 't' и т. Д.

Итакто, что мы собираемся сделать, это следующее:

  1. (я полагаю, вы уже можете выполнить эту часть) Создать словарь фактической частоты букв в зашифрованном тексте.

  2. Мы определяем функцию, которая берет словарь {буква: частота} и создает список букв в порядке частоты.

  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.
0 голосов
/ 13 декабря 2010
#!/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
0 голосов
/ 13 декабря 2010

Прежде всего, обратите внимание, что очень маловероятно, что частоты дадут вам точное соответствие, если ваше сообщение не очень длинное. Таким образом, вам может потребоваться выполнить ручную настройку, чтобы получить точное сообщение. Но если частоты достаточно близки ...

Вы можете получить ключи обоих словарей (букв), отсортированные по их значениям (частотам):

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)
...