rot13是shift=13的凯撒密码特例,加解密函数完全一致;其核心原理是利用13为26的一半实现大小写字母对称映射,通过模运算统一处理,非字母字符原样保留,且必须用unsigned char和islower/isupper规避符号性与非法输入问题。

ROT13 是凯撒密码的特例(shift = 13),它不需要额外参数、大小写逻辑对称、加解密函数完全一致——直接复用同一段代码即可,无需区分“加密”或“解密”。
为什么 ROT13 不用 if-else 判断大小写边界
因为 13 正好是 26 的一半,大写 'A'–'M' 和 'N'–'Z'、小写 'a'–'m' 和 'n'–'z' 两两互为映射。所以只要统一做 c += 13 或 c -= 13,再用模运算兜底,就能覆盖全部情况。但更简洁安全的做法是:对每个字母都走同一套公式,避免分支遗漏。
- 小写字母:用
'a' + (c - 'a' + 13) % 26 - 大写字母:用
'A' + (c - 'A' + 13) % 26 - 非字母字符(空格、数字、标点)必须原样保留,
std::isalpha是唯一可靠判断依据 - 传入
std::isalpha前必须转unsigned char,否则在 glibc 等平台可能触发未定义行为
标准实现里最容易崩的三处细节
看似几行代码,实际运行时崩溃或乱码,往往卡在这几个点:
-
std::isalpha(c)直接传char:若char为有符号且值为负(如读文件时遇到高位字节),会传入非法值,glibc 下直接 abort - 用
s.at(i)修改字符串:越界时抛std::out_of_range,而s[i]是未定义行为(不抛异常但可能静默失败) - 忘记处理
char的符号性:比如char c = '\xff'; c += 13在有符号 char 平台溢出成负数,后续减'a'导致大负数,模运算结果不可控
正确做法是统一用 static_cast<unsigned char>(c)</unsigned> 转换后再参与所有计算。
一个能直接粘贴进项目的 ROT13 函数
这个版本规避了上述所有坑,支持任意 ASCII 字符串输入,返回新字符串(不修改原串):
std::string rot13(const std::string& s) {
std::string out = s;
for (char& c : out) {
unsigned char uc = static_cast<unsigned char>(c);
if (std::islower(uc)) {
c = 'a' + (uc - 'a' + 13) % 26;
} else if (std::isupper(uc)) {
c = 'A' + (uc - 'A' + 13) % 26;
}
// 非字母字符不做任何改动
}
return out;
}
</unsigned>
- 不用
std::isalpha先判再分,而是用std::islower/std::isupper直接分流——更精准,也避免std::isalpha('\xFF')这类非法输入 - 所有算术运算都在
unsigned char范围内进行,彻底规避符号扩展和负值模问题 - 没有
+=或-=,全部用赋值,防止中间态溢出影响后续逻辑
真正容易被忽略的是:ROT13 对 UTF-8 中文完全无效。如果输入含中文,std::islower 返回 false,但后续 uc - 'a' 仍会执行(只是结果无意义),最终输出仍是乱码字节。它只承诺对纯 ASCII 文本可靠——这不是缺陷,是设计前提。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











