Как использовать арифметику по модулю для реализации шифра Цезаря

Я пытаюсь выполнить обтекание символов алфавита ASCII, чтобы выполнить переход от клавиши. Например, если ключ 2, сдвиньте букву A становиться C, Но как мне обернуть Z чтобы добраться до B используя модуль арифметики?

Я пытаюсь реализовать следующую формулу:

ci = (pi + key) % 26;

куда ci это iзашифрованное письмо и pi это iэто письмо должно быть зашифровано.

4 ответа

Другие уже продемонстрировали основную концепцию вычитания смещения букв ASCII, но вы должны быть осторожны при переходе от заглавных букв к заглавным, поскольку между ними есть некоторые символы, которые, я думаю, вы хотите избежать. Я добавил некоторую логику, которая допускает отрицательные сдвиги и удерживает букву в пределах заглавной или не заглавной буквы и проверяет, является ли она буквой вообще.

#include <stdio.h>

#define ASCII_CAP_LETTER_OFFS 65
#define ASCII_LETTER_OFFS 97
#define NUM_OF_LETTERS 26

char shift_letter (char letter, short shift)
{
  char ci;
  short shift_lcl = shift % NUM_OF_LETTERS;
  if (shift_lcl >= 0)
  { // shift in positive direction
  }
  else
  { // shift in negative direction 
   shift_lcl = NUM_OF_LETTERS + shift_lcl;
  }

  if (letter >= ASCII_CAP_LETTER_OFFS && letter < ASCII_CAP_LETTER_OFFS + NUM_OF_LETTERS)  
    {// its a capital letter
      ci =
    (letter + shift_lcl - ASCII_CAP_LETTER_OFFS) % NUM_OF_LETTERS +
    ASCII_CAP_LETTER_OFFS;
    }
  else if (letter >= ASCII_LETTER_OFFS && letter < ASCII_LETTER_OFFS + NUM_OF_LETTERS) 
    {// its a non capital letter
      ci =
    (letter + shift_lcl - ASCII_LETTER_OFFS) % NUM_OF_LETTERS +
    ASCII_LETTER_OFFS;
    }
  else
    {
      printf ("This was not a letter!\n");
      ci = 0;
    }
  return ci;
}

int main ()
{
  char test_letter = 'a';
  short test_shift = -53;
  char shifted_letter = 0;
  shifted_letter = shift_letter (test_letter, test_shift);
  printf("%c +  %d = %c", test_letter, test_shift, shifted_letter);
}

Я считаю, что вам нужно работать с "относительными" значениями, а не с абсолютными значениями.

Используйте что-то вроде

ci = ((pi - 'A' + key) % 26 ) + 'A';

Символьные целочисленные константы хранят закодированные значения, в данном случае ASCII. Вот, 'A' начинается со смещения (десятичное значение 65), а не с 0. Итак, перед тем как вы можете обернуть результат, используя % 26 операция, вы должны получить это смещение. После завершения вычисления добавьте смещение назад, чтобы получить правильное представление ASCII.

Глубже

 ci = ((pi - 'A' + key) % 26) + 'A';

а также ответ @Sourav Ghosh генерирует ожидаемый закодированный AZ, когда key неотрицателен и не слишком велик. Это уменьшает pi с - 'A' так что значение в [0...25] диапазон и смещает его после % расчет.

Работать по полной int диапазон key занимает немного больше кода.

  • уменьшить key спектр [INT_MIN...INT_MAX] с функциональным эквивалентным диапазоном [-25 ... 25] с key % 26, Этот шаг важен для предотвращения intпереполнение pi - 'A' + key, Это можно сделать один раз, если нужно закодировать несколько букв.

  • Добавьте 26. Это гарантирует, что отрицательные ключи будут перемещены в положительные.

    ci = ((pi - 'A' + key%26 + 26) % 26 ) + 'A';
    

Примечание: в С, % это не оператор мода, а оператор остатка. Функциональные различия происходят с a%b когда a и / или b отрицательны. ссылка

Сурав Гхош уже ответил на ваш вопрос.

Но это еще один способ сделать это.

Случай 1:

#include<stdio.h>
int main()
{
  char pi = 'Z';
  char key = 2;
  char offset = pi+key;
  char ci =('A'+(offset%'A')%26);
  printf("%c",ci);
}

Выход:

В

Вариант 2:

#include<stdio.h>
int main()
{
  char pi = 'Z';
  char key = 0;
  char offset = pi+key;
  char ci =('A'+(offset%'A')%26);
  printf("%c",ci);
}

Выход:

Z

Вопрос 3:

#include<stdio.h>
int main()
{
  char pi = 'Z';
  char key = -1;
  char offset = pi+key;
  char ci =('A'+(offset%'A')%26);
  printf("%c",ci);
}

Выход:

Y

Другие вопросы по тегам