Шифр Цезаря: как вычислить со значением сдвига › 10 (или больше)?

Насколько я знаю, "формула" Цезаря сдвига (x + k) % 26, где k - значение сдвига, а расшифровка просто заменяет "+" на "-".

но мой код не работает, когда k> 10 (после того, как я проверил k = 10, я обнаружил, что «сдвиг» первых нескольких символов неверен, поэтому я оцениваю, что k> 10 будет неправильным (количество неправильных символов увеличивается ) также. ). Сначала я меняю символы на ASCII, а затем делаю расчет. Наконец, измените его обратно на символы.

Вот мой код.

#include <iostream>
#include <string>
using namespace std;
int main() {
    string target;
    char s;
    int k, i, num, length, j;
    cin >> s >> k;
    getline(cin, target);

    for (j = 0; j <= (int)target.length(); j++) {
        if ((target[j]) = ' ') {
            target.erase(j, 1);
        }
    }

    length = (int)target.length();

    if (s == 'e') {
        for (num = 0; num <= length; num++) {

            if (isupper(target[num]))
                target[num] = tolower(char(int(target[num] + k - 65) % 26 + 65));
            else if (islower(target[num]))
                target[num] = toupper(char(int(target[num] + k - 97) % 26 + 97));
        }
    }
    else if (s == 'd') {
        for (num = 0; num <= length; num++) {
            if (isupper(target[num]))
                target[num] = tolower(char(int(target[num] - k - 65) % 26 + 65));
            else if (islower(target[num]))
                target[num] = toupper(char(int(target[num] - k - 97) % 26 + 97));
            }
        }
    cout << target;
    return 0;
}

Позвольте мне отложить дело, которое мне не удалось запустить.

вход:

d 10 n 3 V 3 D 3 N _ M Y N 3 _ S C _ N 3 L E (сначала введите d / e, затем сдвиньте значение, наконец, последовательность строк требует «изменить», пробел требуется для удаления.)

ожидаемый результат:

D3l3t3d_cod3_is_d3bu

мой вывод:

D3l3:3d_cod3_i9_d3b; Спасибо!


person eulerisgod    schedule 22.02.2019    source источник
comment
A и a имеют гораздо больше смысла, чем 65 и 97.   -  person molbdnilo    schedule 22.02.2019
comment
Это очень загадочное утверждение: мой код не работает, когда k > 10 (на самом деле я тестировал только k = 10).   -  person molbdnilo    schedule 22.02.2019
comment
извините за это, после того, как я проверил k = 10 , я обнаружил, что сдвиг первых нескольких символов неверен, поэтому я оцениваю, что k > 10 также будет неправильным (количество неправильных символов увеличивается).   -  person eulerisgod    schedule 22.02.2019
comment
Я просто редактирую сообщение, извините за неясность   -  person eulerisgod    schedule 22.02.2019


Ответы (1)


Ваша проблема в том, что при декодировании вы получаете отрицательные числа. С k == 13 выражение 'T' - k - 65 дает -7. -7 % 26 по-прежнему -7. -7+65 это 58, что не является буквой.

Вы можете избежать отрицательных чисел, просто установив k в 26 - k при декодировании.

Затем ваш код упрощается до:

if (s == 'd') {
    k = 26 - k;
}
for (num = 0; num <= length; num++) {

    if (isupper(target[num]))
        target[num] = tolower(char(int(target[num] + k - 'A') % 26 + 'A'));
    else if (islower(target[num]))
        target[num] = toupper(char(int(target[num] + k - 'a') % 26 + 'a'));
}

Примечание. Я заменил ваши целочисленные константы их эквивалентными символами, что значительно упрощает понимание кода. Обратите внимание, что у вас также есть ошибка в первом цикле (target[j]) = ' ' должно быть (target[j]) == ' '.

Используя все возможности С++, вы можете сократить свой код до:

#include <iostream>
#include <string>
#include <algorithm>

int main() {
    std::string target = "mXLM";
    char s = 'e';
    int k = 7;

    target.erase(std::remove(target.begin(), target.end(), ' '), target.end());

    if (s == 'd') {
        k = 26 - k;
    }
    std::string result;
    std::transform(target.begin(), target.end(), std::back_inserter(result), [k](char in) {
        if (isalpha(in)) {
            char inputOffset = isupper(in) ? 'A' : 'a';
            char outputOffset = isupper(in) ? 'a' : 'A';
            return char(int(in + k - inputOffset) % 26 + outputOffset);
        }
        return in;
    });
    std::cout << result;
    return 0;
}
person Alan Birtles    schedule 22.02.2019
comment
Большое спасибо ! Оно работает ! но мне интересно, почему я использую (target[j]) = ' ' все еще могу получить вывод, в чем ошибка? Кстати, ваш сокращенный код намного интереснее, ха-ха! - person eulerisgod; 22.02.2019
comment
Не знаю, у меня не сработало, просто стер большую часть строки - person Alan Birtles; 22.02.2019
comment
Поскольку каждый другой символ вашего ввода является пробелом, другая ошибка в вашем цикле увеличения j после стирания работает в вашу пользу, безоговорочно удаляя все остальные символы. - person Alan Birtles; 22.02.2019
comment
Я попробовал свой примерный случай, такая же ситуация, как у вас. Извините за это ~ Тем не менее, спасибо за объяснение! - person eulerisgod; 22.02.2019