S. Это будет наш секрет

Шифр Цезаря, также известный как шифр сдвига, код Цезаря — один из самых простых и наиболее широко известных методов шифрования. Он назван в честь римского полководца Гая Юлия Цезаря, использовавшего его для секретной переписки со своими генералами.

Давайте реализуем эту систему шифрования. Однако для простоты мы будем сдвигать только латинские символы по кругу.

Формат ввода

Вводится размер сдвига для шифрования.

В файле public.txt содержится текст на английском языке.

Формат вывода

В файл private.txt запишите зашифрованный текст.

Пример

Ввод

# Пользовательский ввод
3

# Содержимое файла public.txt
Hello, world!

Вывод

# Содержимое файла private.txt
Khoor, zruog!

Ввод

# Пользовательский ввод
-10

# Содержимое файла public.txt
English alphabet: ABCDEFG...XYZ

Вывод

# Содержимое файла private.txt
Udwbyix qbfxqruj: QRSTUVW...NOP

Решение

Реализация шифра Цезаря не самая сложная задача. Ее можно поделить на две стадии – фильтрация текста для того, чтобы определить нужно ли изменять букву и непосредственно манипуляция с буквой, если да.

Проблему обычно представляет только сам процесс манипуляции. Есть два основных подхода – Работа через функции chr/ord и работа через списки/словари на уровне создания алфавита подмен.

Метод работы через chr/ord довольно громоздкий и недостаточно универсальный в силу того, что коды букв в файлах на разных платформах могут очень сильно отличаться. Ко мне обращались ученики, которые протестировав программу на windows сталкивались с тем, что она не срабатывала при попытке сдать тест. Все дело в том, то они забывали указать параметр encoding при чтении файла и работали с буквами в родной для windows кодировке CP1251, где коды символов очень сильно отличаются от кодов символов родной для пайтона UTF-8. Если бы работа шла через словари и списки, то неладное заподозрили бы сильно раньше, потому что в python ‘a’ будет означать букву а именно в кодировке UTF-8.

Итак в чем состоит идея шифра Цезаря? Перебирая буквы, мы определяем нужно ли ее кодировать. Если да, то к коду буквы прибавляется число, равное сдвигу, после чего получившийся код преобразуется в букву. Так как английские буквы расположены по-порядку то таким нехитрым способом можно реализовать требуемый сдвиг всего алфавита. Единственная проблема – буквы, расположеные в конце алфавита. Дело в том, что при сдвиге буква может “уйти” из диапазона букв алфавита. Поэтому при добавлении сдвига важно контролировать, чтобы буква оставалась в диапазоне кодов, и если новое значение кода превысило код последней буквы алфавита, вычитать из кода размер алфавита, возвращая, таким образом код в начало алфавита. В этом методе есть и другая проблема – так как у нас есть отдельно прописные и строчные буквы, нам потребуется отслеживать два диапазона. Кроме того, некоторые языки(включая русский) содержат отдельные от остальных буквы.

При использовании списков или словарей, мы сильно упрощаем как сам расчет, так и контроль границ – буквы после сдвига просто не могут выйти за пределы алфавита, так как мы всегда будем получать правильный готовый результат. Но сначала нам нао подготовить две сущности – сам алфавит abcdefghijklmnopqrstuvwxyzи его “сдвинутую” версию. В качестве примера возьмем сдвиг из первого тестового случая. У нас это будет три. Таким образом, отрезаем три буквы от начала алфавита и переклеиваем их в конец – defghijklmnopqrstuvwxyzabc. Теперь для кодирования нам достаточно вычислить позицию буквы в первом списке, и взять букву, с тем же порядковым номером из второго. Остается только решить проблему с заглавными буквами, ведь наш с вами алфавит не содержит заглавных букв. Эта проблема решается очень просто. При проверке на принадлежность алфавиту мы все символы приводим к нижнему регистру. а при кодировании проверяем, если буква в исходном тексте была заглавная, то переводим букву второго алфавита в верхний регистр. Мы это уже проделывали в задачах J. Транслитерация и F. Транслитерация 2.0.

Еще больше упростить задачу можно, если создать “словарь замен”. Для этого просто объединяем два списка в словарь, где ключом будет исходная буква, а значением – буква из списка заменю.

Остается учесть всего один нюанс – значение сдвига может быть больше размера словаря, или отрицательным числом. В этом случае достаточно получить модуль от деления сдвига на размер словаря.

Посмотреть код

Решение

Python
file_in = 'public.txt'
file_out = 'private.txt'

a = ord('a')
z = ord('z')

shift = int(input()) % 26

with open(file_in, encoding='UTF-8') as file:
    data = file.read()

    output = ''

    for i in range(len(data)):
        pos = a
        if a <= (code := ord(data[i].lower())) <= z:
            pos = code + shift
            if pos > z:
                pos -= 26
            elif pos < a:
                pos += 26
            output += chr(pos).upper() if data[i].isupper() else chr(pos)
        else:
            output += data[i]

# print(output)
with open(file_out, 'w', encoding='UTF-8') as file:
    file.write(output)

Решение

Python
file_in = 'public.txt'
file_out = 'private.txt'

alphabet = 'abcdefghijklmnopqrstuvwxyz'

shift = int(input()) % len(alphabet)

shifted_alphabet = alphabet[shift:] + alphabet[:shift]
output = ''

with open(file_in, encoding='UTF-8') as file:
    data = file.read()

    for char in data:
        new_char = char
        if char.lower() in alphabet:
            pos = alphabet.find(char.lower())
            new_char = shifted_alphabet[pos]
        output += new_char.upper() if char.isupper() else new_char

# print(output)
with open(file_out, 'w', encoding='UTF-8') as file:
    file.write(output)

Решение

Python
file_in = 'public.txt'
file_out = 'private.txt'

chars = 'abcdefghijklmnopqrstuvwxyz'

shift = int(input()) % len(chars)

shifted_chars = chars[shift:] + chars[:shift]

alphabet = {key: value for key, value in zip(chars, shifted_chars)}
output = ''

with open(file_in, encoding='UTF-8') as file:
    data = file.read()

    for char in data:
        new_char = alphabet[char.lower()] if char.lower() in alphabet else char
        output += new_char.upper() if char.isupper() else new_char

# print(output)
with open(file_out, 'w', encoding='UTF-8') as file:
    file.write(output)
Подписаться
Уведомить о
guest
0 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии