Vigenere Cipher работает только до пробела (" ") в C - почему?

 #include <stdio.h>
 #include <cs50.h>
 #include <string.h>
 #include <stdlib.h>
 #include <ctype.h>

 int main(int argc, string argv[])
 {
      string k = argv[1];
      string s = GetString();
      int l = strlen(k);

      for(int i = 0, n = strlen(s); i < n; i++)
      {
          if(s[i] >= 65 && s[i] <= 90)
          {
              int i2 = ((s[i]-65) + (k[i%l]-97)) % 26;
              printf("%c", i2+65);
          } else if(s[i] >= 97 && s[i] <= 122)
          {
              int i2 = ((s[i]-97) + (k[i%l]-97)) % 26;
              printf("%c", i2+97);
          } else
          {
              printf("%c", s[i]);
          }
      }
      printf("\n");
      return 0;
 }

Я удалил столько частей, сколько смогу, чтобы сделать код более актуальным для вопроса. В основном, почему этот код работает, когда в "s" нет пробела (" ") и нет, когда "s" состоит из пробела (" ")?

Как большинство из вас может знать, идея заключается в том, что аргумент, введенный в argv[1], является "ключевым словом" для шифра. Затем пользователь вводит "обычный текст" для шифрования (-й). Он работает, когда я пытаюсь использовать разные слова или предложения, если в нем нет пробела, "". Я просто не понимаю логику этого. Почему цикл прерывается, если s[i] это не одно из первых двух условий - я бы подумал, что "другое" условие сработает.

Я был бы очень признателен, если бы кто-то смог пролить свет на это - большое спасибо заранее!

PS: я знаю, что есть некоторые дополнительные библиотеки в верхней части и пользовательский ввод в argv[1] не подтверждено с помощью isalpha(), Я просто хочу лучше понять процесс цикла, у меня есть эти проверки в другом файле.

1 ответ

Решение

Вот код, который реализует комментарий "отдельные счетчики для строки и ключа", который я сделал. Он также использует буквенные коды 'a' а также 'A' (и избегает необходимости использования 'z' или же 'Z') вместо использования чисел. Предполагается, что вы имеете дело с однобайтовым кодовым набором (не UTF-8, если вы не работаете в диапазоне ASCII), где строчные и прописные буквы находятся в непрерывном диапазоне (так что это Надежно работает с EBCDIC, но будет работать с большинством других кодовых наборов), а также игнорирует символы с ударением. (Это должно было бы сделать setlocale("") чтобы получить специфичные для локали интерпретации того, какие символы являются буквами.)

#include <cs50.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>

int main(int argc, string argv[])
{
    if (argc != 2)
    {
        fprintf(stderr, "Usage: %s key\n", argv[0]);
        return 1;
    }

    string k = argv[1];
    int l = strlen(k);

    for (int i = 0; i < l; i++)
    {
        int c = k[i];
        if (!isalpha(c))
        {
            fprintf(stderr, "%s: non-alpha character %c in key string\n", argv[0], c);
            return 1;
        }
        k[i] = tolower(c);
    }

    printf("Enter a string to be encrypted:\n");
    string s = GetString();
    int n = strlen(s);

    for (int i = 0, j = 0; i < n; i++)
    {
        int c = (unsigned char)s[i];
        if (isupper(c))
            c = ((c - 'A') + (k[j++ % l] - 'a')) % 26 + 'A';
        else if (islower(c))
            c = ((c - 'a') + (k[j++ % l] - 'a')) % 26 + 'a';
        putchar(c);
    }
    putchar('\n');

    return 0;
}

Вот примерный прогон, который демонстрирует слабость использования "a" в качестве одной из букв в ключе для этого шифра Vigenere:

./vc caesArandAbrAcaDabRa
Enter a string to be encrypted: 
It is reported that Caesar said "Veni, vidi, vici" when he conquered Britain.
Kt mk rvpbutfu tjaw Cbvscr wsiu "Vrqi, wzdk, vlcj" nhgn lw cfndxesvd Drltbzn.
Другие вопросы по тегам