首页 > 解决方案 > 凯撒密码帮助,找出空格、整数和特殊字符

问题描述

我正在尝试在 C 中创建凯撒密码,但在加密和解密空格、整数和特殊字符(如!$#等)时遇到问题。我有一个简单的代码来计算字符串部分并转换它们。任何建议都会很可爱!让我的代码变得更好的建议也会有所帮助。

这是我的代码:

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

// Ascii codes: 'a'=97, 'b' = 98, and so on.

void encrypt()
{
    char message[500], c;
    int i;
    int key;

    printf("Enter a message to encrypt: ");
    scanf("%s", &message);
    printf("Enter key: ");
    scanf("%d", &key);

    for (i = 0; message[i] != '\0'; i++) {
        c = message[i];
        if (c >= 'a' && c <= 'z') {
            c = c + key;
            if (c > 'z') {
                c = c - 'z' + 'a' - 1;
            }
            message[i] = c;
        } else if (c >= 'A' && c <= 'Z') {
            c = c + key;
            if (c > 'Z') {
                c = c - 'Z' + 'A' - 1;
            }
            message[i] = c;
        }
    }

    printf("Encrypted message: %s", message);
}

void decrypt()
{
    char message[500], c;
    int i;
    int key;

    printf("Enter a message to decrypt: ");
    scanf("%s", &message);
    printf("Enter key: ");
    scanf("%d", &key);

    for (i = 0; message[i] != '\0'; i++) {
        c = message[i];
        if(c >= 'a' && c <= 'z') {
            c = c - key;
            if (c < 'a') {
                c = c + 'z' - 'a' + 1;
            }
            message[i] = c;
        } else if(c >= 'A' && c <= 'Z') {
            c = c - key;
            if(c < 'A') {
                c = c + 'Z' - 'A' + 1;
            }
            message[i] = c;
        }
    }

    printf("Decrypted message: %s", message);
}

int main()
{
    encrypt();
    return 0;
}

标签: cstringcharcaesar-cipher

解决方案


Caesar cipher-wikipedia中描述了该算法。您已经发现值的变化将需要您考虑距离范围末端的偏移量,这很好。遇到问题的地方,在这两种情况下都是对字符的(移位)的加减key以及随后的大于'z'或小于的测试'a'

        c = c + key;
        if (c > 'z') {

        c = c - key;
        if (c < 'a') {

如果添加或减去key(移位值)不会导致值大于'z'或小于'a',(并且不能保证它们会或不会基于key大小),则您根本不会应用任何编码或解码,除非您的条件测试为

该算法要求(x + n)or(x - n)结果必须介于 之间0 - 25。(请参阅链接中的算法)这是% 26用于防止值超过时的方法25,但您还必须确保该值是非负的。您可以通过添加和加上一点代数来满足这个要求,26从而得出一个涵盖所有情况的表达式(一个代表大写,一个代表小写)。例如:

#define SIZE 26
...
int encipher (int c, int shift)
{
    if ('A' <= c && c <= 'Z')
        /*
         *   c = 'A' + (c - 'A' + 'Z' - shift + 1 - 'A') % SIZE;
         *   c = 'A' + (c - 'A' - shift + 'Z' - 'A' + 1) % SIZE;
         *   where ('Z' - 'A' + 1 == SIZE)
         */
        c = 'A' + (c - 'A' - shift + SIZE) % SIZE;
    else if ('a' <= c && c <= 'z')
        c = 'a' + (c - 'a' - shift + SIZE) % SIZE;
    
    return c;
}

和解码:

int decipher (int c, int shift)
{
    if ('A' <= c && c <= 'Z')
        /*
         *   c = 'A' + (c - 'A' - ('Z' - shift + 1 - 'A')) % SIZE;
         *   c = 'A' + (c - 'A' - 'Z' + shift - 1 + 'A') % SIZE;
         *   c = 'A' + (c - 'Z' + shift - 1) % SIZE;
         *   where (c - 'Z' < 0) for (shift - 1 < SIZE)
         */
        c = 'A' + (c - 'Z' + shift - 1 + SIZE) % SIZE;
    else if ('a' <= c && c <= 'z')
        c = 'a' + (c - 'z' + shift - 1 + SIZE) % SIZE;
    
    return c;
}

添加一个简短的示例,允许您输入班次(您的key)和要编码和解码的文本(最多 1024 个字符,1023 + 空字符),您可以这样做:

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

#define SIZE 26
#define MAXC 1024

int encipher (int c, int shift)
{
    if ('A' <= c && c <= 'Z')
        /*
         *   c = 'A' + (c - 'A' + 'Z' - shift + 1 - 'A') % SIZE;
         *   c = 'A' + (c - 'A' - shift + 'Z' - 'A' + 1) % SIZE;
         *   where ('Z' - 'A' + 1 == SIZE)
         */
        c = 'A' + (c - 'A' - shift + SIZE) % SIZE;
    else if ('a' <= c && c <= 'z')
        c = 'a' + (c - 'a' - shift + SIZE) % SIZE;
    
    return c;
}

int decipher (int c, int shift)
{
    if ('A' <= c && c <= 'Z')
        /*
         *   c = 'A' + (c - 'A' - ('Z' - shift + 1 - 'A')) % SIZE;
         *   c = 'A' + (c - 'A' - 'Z' + shift - 1 + 'A') % SIZE;
         *   c = 'A' + (c - 'Z' + shift - 1) % SIZE;
         *   where (c - 'Z' < 0) for (shift - 1 < SIZE)
         */
        c = 'A' + (c - 'Z' + shift - 1 + SIZE) % SIZE;
    else if ('a' <= c && c <= 'z')
        c = 'a' + (c - 'z' + shift - 1 + SIZE) % SIZE;
    
    return c;
}

int main (void) {
    
    int n = 0, shift;
    char text[MAXC],
        encode[sizeof text],
        decode[sizeof text];
    
    fputs ("enter shift: ", stdout);    /* just use text for both inputs */
    if (!fgets (text, MAXC, stdin))
        return 1;
    
    if (sscanf (text, "%d", &shift) != 1) {
        fputs ("error: invalid integer input.\n", stderr);
        return 1;
    }
    
    fputs ("\ninput : ", stdout);
    if (!fgets (text, MAXC, stdin))
        return 0;
    
    text[strcspn(text, "\n")] = 0;      /* trim trailing \n */
    
    do  /* encode text */
        encode[n] = encipher(text[n], shift);
    while (text[n++]);
    
    n = 0;
    do  /* decode encoded text */
        decode[n] = decipher(encode[n], shift);
    while (encode[n++]);
    
    printf ("encode: %s\ndecode: %s\n", encode, decode);
}

注意:在加密的实践中,编码很少表示为以 nul 结尾的字符串。这里由于结果仅限于 ASCII 字符,这便于输出并且适合练习,但通常您只会存储编码值和字符数的计数)

示例使用/输出

用字母检查大写和小写:

$ ./bin/ceasar_cipher
enter shift: 3

input : ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz
encode: XYZABCDEFGHIJKLMNOPQRSTUVW xyzabcdefghijklmnopqrstuvw
decode: ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz

检查维基百科示例:

$./bin/ceasar_cipher
enter shift: 3

input : THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG
encode: QEB NRFZH YOLTK CLU GRJMP LSBO QEB IXWV ALD
decode: THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG

如果您还有其他问题,请仔细查看并告诉我。


推荐阅读