CS50 PSSet 2: Замена

Руководство по проблеме Подмена в CS50, неделя 2.

Цель: Написать программу на C, которая реализует шифр замены, как показано ниже.

$ ./substitution JTREKYAVOGDXPSNCUIZLFBMWHQ
plaintext:  HELLO
ciphertext: VKXXN

Программа должна шифровать только буквы, независимо от того, прописные они или строчные.

$ ./substitution VCHPRZGJNTLSKFBDQWAXEUYMOI
plaintext:  hello, world
ciphertext: jrssb, ybwsp

Он должен принимать только один аргумент командной строки, ключ, который будет использоваться для подстановки. Этот ключ должен иметь длину ровно 26 символов, принимать только буквы и не учитывать регистр.

Затем он должен запросить открытый текст и вернуть зашифрованный зашифрованный текст.

Сначала мы импортируем необходимые библиотеки и определяем константу N, которая представляет собой требуемую длину ключа, и строку символов в алфавите.

#include <stdio.h>
#include <cs50.h>
#include <ctype.h>
#include <string.h>
const int N = 26;
const string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

Затем объявите функцию main() и убедитесь, что она может принимать только один аргумент командной строки.

int main(int argc, string argv[])
{
    // Check for correct number of args
    if (argc != 2)
    {
        printf("Please provide one command line argument only.\n");
        return 1;
    }

Если эта проверка пройдена, программа может продолжить работу, и мы можем проверить правильность аргумента командной строки. Это должно соответствовать следующим условиям:

  1. Можно использовать только буквы.
  2. Не должно быть повторяющихся букв.

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

Затем ключ можно перебирать символ за символом, сначала проверяя, есть ли только буквы, используемые с несколькими основными операторами и оператором if.

        // Check validity of key content
        int letters[N];
        for (int i = 0, n = strlen(argv[1]); i < n; i++)
        {
            // Check only letters are used
            if (!((argv[1][i] >= 'a' && argv[1][i] <= 'z') || 
                  (argv[1][i] >= 'A' && argv[1][i] <= 'Z')))
            {
                printf("Key must contain only letters.\n");
                return 2;
            }

Если эта проверка пройдена, я преобразую весь ключ в верхний регистр с помощью toupper() по причинам, которые станут ясны позже.

            // Convert to uppercase
            else if (argv[1][i] >= 'a' && argv[1][i] <= 'z')
            {
                argv[1][i] = toupper(argv[1][i]);
            }

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

            // Check for repeated letters
            for (int j = 0; j < N; j++)
            {
                if (argv[1][i] == letters[j])
                {
                    printf("Key must not contain repeated     letters.\n");
                    return 3;
                }
            }
            
            letters[i] = argv[1][i];
        }

С этими проверками, переданными в аргументе командной строки, программа теперь может запросить у пользователя шифрование ввода. Здесь также определяется массив пустого зашифрованного текста с длиной l + 1, чтобы оставить место для нулевого терминатора.

        // Ask for plaintext
        string plaintext = get_string("plaintext: ");
        int l = strlen(plaintext);
        char ciphertext[l + 1];

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

См. также:  Прогнозирование дефолта по ссуде с помощью набора данных Berka

Внутренний цикл проходит по алфавиту, чтобы проверить, является ли символ обычного текста буквой или нет. Если это так, символ простого текста преобразуется в зашифрованный текст с использованием соответствующего индекса ключа шифрования.

        // Convert to ciphertext
        // Loop through each char in plaintext
        for (int i = 0; i < l; i++)
        {
            // Check if uppercase and if so use standard  alphabet/key
            if (isupper(plaintext[i]) != 0)
            {
                for (int j = 0; j < N; j++)
                {
                    if (plaintext[i] == alphabet[j])
                    {
                        ciphertext[i] = argv[1][j];
                        break;
                    }
                }
            }

Аналогичный процесс можно выполнить, если обычный текстовый символ имеет нижний регистр, что проверяется с помощью функции islower(). Эта функция повторяется для преобразования в символ шифрованного текста нижнего регистра.

            // If lowercase use lowercase alphabet and key
            else if (islower(plaintext[i]) != 0)
            {
                for (int j = 0; j < strlen(alphabet); j++)
                {
                    if (plaintext[i] == tolower(alphabet[j]))
                    {
                        ciphertext[i] = tolower(argv[1][j]);
                        break;
                    }
                }
            }

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

            // Finally replace non letters
            else
            {
                ciphertext[i] = plaintext[i];
            }
        }

Наконец, добавьте нулевой символ в конец зашифрованного текста, чтобы сделать его строкой, и распечатайте результат.

        // Add null char to make it a string
        ciphertext[l] = '\0';
        // Print result and exit
        printf("ciphertext: %s\n", ciphertext);
        return 0;
    }
}

И это замена, наше первое, но определенно не последнее знакомство с использованием аргументов командной строки и всем, что с ними связано.

Понравилась статья? Поделиться с друзьями:
IT Шеф
Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: