土耳其字符导致凯撒加解密失效的原因问询(VS C++/CodePage1254)
凯撒加密解密对土耳其字符失效的问题解决
问题描述
使用Visual Studio C++项目编写的凯撒加密解密代码,处理非土耳其字符时运行正常,但采用Turkish(Windows)-CodePage 1254编码时,输入如“öğrenci”,解密后实际输出“§renci”,无法还原为原字符串。原代码如下:
#define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <stdio.h> #include<stdlib.h> #include<locale.h> #include<conio.h> #include<string.h> void ceaserEncrypt(char* point) { setlocale(LC_ALL, "turkish"); char msg0[100]; char msg1[100]; char* ptrmsg = msg1; printf("Şifrelenecek metni giriniz:"); gets(msg0, sizeof(msg0)); system("cls"); int i; for (i = 0;msg0[i] != '\0';i++) { if (msg0[i] != ' ') { msg1[i] = msg0[i] + 5; } else { msg1[i] = ' '; } } msg1[i] = '\0'; printf("encryption:%s", msg1); strcpy(point, msg1); } char a[100]; char* ptr = a; void ceaserDecrypt(char str[]) { setlocale(LC_ALL, "turkish"); char msg0[100]; strcpy(msg0, str); int i; for (i = 0;i < strlen(msg0);i++) { if (msg0[i] != ' ') { msg0[i] = msg0[i] - 5; } else { msg0[i] = ' '; } } printf("\nDecryption:%s", msg0); } int main(){ ceaserEncrypt(ptr); ceaserDecrypt(a); return 0; }
问题原因
原代码直接对字符的字节值进行加减操作,未考虑土耳其字符集(CodePage 1254)的特性:
- 土耳其字母包含ç、ğ、ı、ö、ş、ü等特有字符,这些字符的字节值加减5后会跳出有效字母范围,变成非字母符号
- 凯撒密码的核心是在对应语言的字母表内循环偏移,而非直接修改字节值,原逻辑未实现循环机制,导致字符偏移后无法正确还原
修正方案
定义土耳其字母表的大小写集合,加密解密时在字母表范围内循环偏移5位,确保字符始终保持在有效字母范围内:
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include<stdlib.h> #include<locale.h> #include<string.h> // 土耳其字母表(含大小写,按CodePage 1254顺序) const char turkish_lower[] = "abcçdefgğhıijklmnoöprsştuüvyz"; const char turkish_upper[] = "ABCÇDEFGĞHIİJKLMNOÖPRSŞTUÜVYZ"; const int turkish_len = sizeof(turkish_lower) - 1; // 去掉末尾的'\0' // 找到字符在字母表中的索引,未找到返回-1 int find_char_index(char c, const char* alphabet) { for (int i = 0; alphabet[i] != '\0'; i++) { if (alphabet[i] == c) { return i; } } return -1; } void ceaserEncrypt(char* point) { setlocale(LC_ALL, "turkish"); char msg0[100]; char msg1[100]; printf("Şifrelenecek metni giriniz:"); fgets(msg0, sizeof(msg0), stdin); // 去掉fgets读取的换行符 msg0[strcspn(msg0, "\n")] = '\0'; system("cls"); int i; for (i = 0; msg0[i] != '\0'; i++) { if (msg0[i] == ' ') { msg1[i] = ' '; continue; } int idx = find_char_index(msg0[i], turkish_lower); if (idx != -1) { // 小写字母循环偏移5位 msg1[i] = turkish_lower[(idx + 5) % turkish_len]; continue; } idx = find_char_index(msg0[i], turkish_upper); if (idx != -1) { // 大写字母循环偏移5位 msg1[i] = turkish_upper[(idx + 5) % turkish_len]; continue; } // 非土耳其字母保持原样 msg1[i] = msg0[i]; } msg1[i] = '\0'; printf("encryption:%s\n", msg1); strcpy(point, msg1); } char a[100]; char* ptr = a; void ceaserDecrypt(char str[]) { setlocale(LC_ALL, "turkish"); char msg0[100]; strcpy(msg0, str); int i; for (i = 0; msg0[i] != '\0'; i++) { if (msg0[i] == ' ') { msg0[i] = ' '; continue; } int idx = find_char_index(msg0[i], turkish_lower); if (idx != -1) { // 小写字母循环偏移-5位,避免负数取模问题 msg0[i] = turkish_lower[(idx - 5 + turkish_len) % turkish_len]; continue; } idx = find_char_index(msg0[i], turkish_upper); if (idx != -1) { // 大写字母循环偏移-5位 msg0[i] = turkish_upper[(idx - 5 + turkish_len) % turkish_len]; continue; } // 非土耳其字母保持原样 msg0[i] = msg0[i]; } printf("Decryption:%s\n", msg0); } int main(){ ceaserEncrypt(ptr); ceaserDecrypt(a); return 0; }
关键修改点
- 替换不安全的
gets为fgets,避免缓冲区溢出 - 定义土耳其专属字母表,实现字符在字母表内的循环偏移
- 增加大小写字母的判断逻辑,确保特殊字符正确偏移
- 解密时通过
+ turkish_len避免负数取模导致的异常
内容的提问来源于stack exchange,提问作者Orhun Tokdemir
相关产品推荐
相关产品推荐

