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

В качестве основы была взята Библия. Никакого религиозного подтекста в этом нет — в первой версии данного алгоритма шифрования использовалась именно это «произведение».

В качестве языка реализации был выбран 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-канал. Там еще больше полезного и интересного для программистов.