一种比较简单的实现方法
我在上小学时候的睡前读物就是《福尔摩斯探案集》,对“跳舞小人”那一章记忆犹新(当时看标题觉得可能是什么恐怖故事,硬是留到了最后才看)。
福尔摩斯解密“跳舞小人”密码的时候,提到了英文中最受欢迎的字母就是‘e’,后来看 《怪诞小镇》 的时候经常用这种方法去尝试破译(虽然没有成功过)。
好了,看这道题。
既然是凯撒加密法,那么我们只要找到密文中对应‘E’的字母,我们就可以找到全部的密码表。
观察这道题的输入,个人认为START和END有些不太必要,可能是为了进一步降低难度。我们使用gets()函数进行读取时,完全可以忽略这两个关键词的影响,跳过就好了,对我们来说真正有用的只有安全词——ENDOFINPUT。
经过测试发现,输入结尾可能是'\r\n'和'\n'。如果结尾是'\r',gets()是会读入的,当然可以用scanf的[ ]去解决。但其实我们只需要在比较判断时,使用 strncmp() 解决就可以了。
还有,当密文出现多个相等最大值时,取后者!
#define _CRT_SECURE_NO_DEPRECATE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int e[30] = { 0 };
int upper(char s[])//字母替换为大写
{
for (int i = 0; s[i] != '\0'; i++)
if (s[i] >= 'a' && s[i] <= 'z')
s[i] = s[i] - 'a' + 'A';
return 0;
}
int finde(char s[])//找到密文‘E’
{
int key = 0, max = 0;
for (int i = 0; s[i] != '\0'; i++)
if (s[i] >= 'A' && s[i] <= 'Z')
{
e[s[i] - 'A']++;
if (e[s[i] - 'A'] >= max)
{
max = e[s[i] - 'A'];
key = s[i];
}
}
key -= 'E';
return key;
}
int main()
{
char s[10010] = "\0";
int key;
while (gets(s))
{
if (strncmp(s, "ENDOFINPUT", 10) == 0)
break;
else if (strncmp(s, "START", 5) == 0 || strncmp(s, "END", 3) == 0)
continue;
else
{
upper(s);
key = finde(s);
}
for (int i = 0; s[i] != '\0'; i++)
{
if (s[i] >= 'A' && s[i] <= 'Z')//简单的处理+输出
{
if (s[i] - key > 'Z')
printf("%c", s[i] - key - 26);
else if (s[i] - key < 'A')
printf("%c", s[i] - key + 26);
else
printf("%c", s[i] - key);
}
else
printf("%c", s[i]);
}
printf("\n");
}
return 0;
}