Добрый день, уважаемые читатели. Сегодня мы реализуем самый простой вариант такого алгоритма, как шифрование текста по книге. Суть шифрования проста — текст разбивается на слова, а каждое слово шифруется парой чисел — (номер строки, номер слова в этой строке). Очевидно, что главным плюсом данного алгоритма является тот факт, что текст можно расшифровать лишь при наличии исходного текста.
В качестве основы была взята Библия. Никакого религиозного подтекста в этом нет — в первой версии данного алгоритма шифрования использовалась именно это «произведение».
В качестве языка реализации был выбран Python.
Подпишись на группу Вконтакте и Телеграм-канал. Там еще больше полезного контента для программистов.
А на YouTube-канале ты найдешь обучающие видео по программированию. Подписывайся!
Предобработка текста и выделение слов
Для начала скачаем текст Библии в виде текстового файла на этом сайте (не реклама). Сохраним его под названием 'Bible.txt'
. Также удалим строки в начале и конце, которые не имеют отношения к тексту самой Библии.
Примечание. Далее материал рассчитан на людей, имеющих опыт работы с языком Python.
Создадим файл Python (.py
) под названием get_dicts.py
. Начнём наш эксперимент с импортирования необходимых модулей стандартной библиотеки.
import string import re import pickle
Затем объявим несколько переменных, которые нам пригодятся в работе.
path = 'Bible.txt' path_for_save = 'Bible_preprocessed.txt' preprocessed_text = str()
Загрузим текст из файла и сохраним только те строки, которые не являются заголовками (такие строки имеют вид «Глава …») или пустыми.
with open(path, 'r') as f: for line in f.readlines(): if not (line == '\n' or line.startswith('Глава')): preprocessed_text += line
Далее приведем полученный текст к нижнему регистру и удалим символы «[» и «]», так как некоторые слова заключены в квадратные скобки.
preprocessed_text = preprocessed_text.lower() preprocessed_text = preprocessed_text.replace('[', '').replace(']', '')
Также удалим все знаки препинания, воспользовавшись string.punctuation
.
for c in string.punctuation: preprocessed_text = preprocessed_text.replace(c, '')
Примечание. Данный вариант является самым простым в реализации, однако не самым быстрым в плане времени работы.
Теперь запишем предобработанный текст в отдельный файл и удалим переменную с текстом, так как она занимает значительное место в оперативной памяти.
with open(path_for_save, 'w') as f:
f.write(preprocessed_text)
del preprocessed_text
Выделение слов и создание словарей
Слова мы будем выбирать с помощью регулярных выражений. Обсуждение данного метода обработки строк символов выходит за рамки этой статьи, однако в сети находится много качественного материала на эту тему. Приступим!
Паттерн [а-я]+
означает строку, состоящую из любого количества букв русского алфавита в нижнем регистре.
re.findall(pattern, text)
находит все строки, которые подходят под шаблон (в нашем случае, все слова русского языка, которые содержатся в Библии).
Перебирая все строки, мы создаем словарь вида <word : indexes>
, где indexes
— список индексов, каждый из которых представляет пару чисел вида (номер строки, номер слова в этой строке).
with open(path_for_save, 'r') as f: count = 0 for line in f.readlines(): words = re.findall(pattern, line) for word in words: if not word in encode_dict: encode_dict[word] = [(count, words.index(word))] else: encode_dict[word].append((count, words.index(word))) count += 1
Далее мы создаем обратный словарь вида <index:word>
, с помощью которого будем расшифровывать текст.
decode_dict = {index:word for word, indexes in encode_dict.items() for index in indexes}
И теперь с помощью модуля pickle
сохраним эти два словаря в бинарные файлы:
with open('encode_dict.pkl', 'wb') as encode: with open('decode_dict.pkl', 'wb') as decode: pickle.dump(encode_dict, encode) pickle.dump(decode_dict, decode)
Запустив этот сценарий Python, мы получим на выходе три файла. 'Bible_preprocessed.txt'
, 'encode_dict.pkl'
и 'decode_duct.pkl'
.
Далее создадим программный интерфейс для шифрования и расшифрования. Создадим файл 'crypt.py'
, в котором, для начала, импортируем необходимые нам модули.
import re import random import pickle
Далее реализуем функцию шифрования, в которой мы:
- определяем паттерн для поиска слов и результирующий список индексов
- приводим исходное предложение к нижнему регистру
- загружаем словарь для шифрования из бинарного файла
- выделяем слова и добавляем список рандомный индекс для этого слова
- возвращаем строку
def encode(sentence:str) -> list: output_list = list() pattern = '[a-я]+' sentence = sentence.lower() with open('encode_dict.pkl', 'rb') as f: encode_dict = pickle.load(f) for word in re.findall(pattern, sentence): if word in encode_dict: output_list.append(random.choice(encode_dict[word])) else: raise ValueError(f'{word} - this word can not to be encoded.') return output_list
Также реализуем функцию расширования, которая в качестве аргумента список индексов:
def decode(indexes:list) -> str: output_string = str() with open('decode_dict.pkl', 'rb') as f: decode_dict = pickle.load(f) for index in indexes: if not index in decode_dict: raise ValueError(f'{index} - this index can not be decoded.') output_string += decode_dict[index] + ' ' return output_string
Теперь остается создать ещё один .py
файл, где мы протестируем наши функции.
from crypt import decode, encode
decoded_sentence = encode('Это наше предложение.')print(decoded_sentence)
print(decode(decoded_sentence))
Вывод этой программы будет:
[(25161, 20), (23690, 11), (28046, 23)]
это наше предложение
Да, наш алгоритм не учитывает регистр и знаки препинания, однако если речь идет о шифровании, то он работает корректно.
Заключение
В этой статье мы подробно рассмотрели шифрование текста по книге. Полученный программный интерфейс подходит для начинающих специалистов в области криптографии как учебный материал :)
На этом статья заканчивается. Если вы заинтересованы в математическом анализе, советую прочитать «Производная. Базовые определения и термины«.
А также подписывайтесь на группу ВКонтакте, Telegram и YouTube-канал. Там еще больше полезного и интересного для программистов.