“字符串减法”实为过滤非中文字符,即从UTF-8编码的std::string中仅保留Unicode汉字(如0x4E00–0x9FFF等区间),需手动解析UTF-8字节序列并判断码点范围。

什么是“字符串减法”:实际是过滤非中文字符
“字符串减法”不是 C++ 标准操作,用户真正想做的是:给定一个 std::string(或 std::u8string),从中**只保留 Unicode 中文字符(即汉字)**,丢弃英文字母、数字、标点、空白、Emoji、ASCII 符号等。关键难点在于:C++ 标准库不直接识别“中文字符”,必须靠 Unicode 码点范围判断。
用 UTF-8 编码 + 手动解析字节:最稳妥的方案
如果输入是 std::string 且内容为 UTF-8 编码(常见于 Linux/macOS 文件、HTTP 响应、现代 C++20 u8"..." 字面量),不能按 char 逐个遍历——因为一个汉字占 3 个字节,单字节判断必然错。必须做 UTF-8 解码:
- 检查首字节确定字节数(0xxxxxxx → 1 字节;110xxxxx → 2 字节;1110xxxx → 3 字节;11110xxx → 4 字节)
- 合并后续字节,还原出 Unicode 码点(
uint32_t) - 判断码点是否落在中文常用区间:
0x4E00–0x9FFF(基本汉字)、0x3400–0x4DBF(扩展 A)、0x20000–0x2A6DF(扩展 B,需 4 字节 UTF-8)
示例核心逻辑(不依赖第三方库):
std::string keep_chinese(const std::string& s) {
std::string out;
size_t i = 0;
while (i < s.size()) {
unsigned char b0 = s[i];
uint32_t cp;
if ((b0 & 0x80) == 0) { // 1-byte
cp = b0;
i += 1;
} else if ((b0 & 0xE0) == 0xC0) { // 2-byte
if (i + 1 >= s.size()) break;
cp = ((b0 & 0x1F) << 6) | (s[i+1] & 0x3F);
i += 2;
} else if ((b0 & 0xF0) == 0xE0) { // 3-byte
if (i + 2 >= s.size()) break;
cp = ((b0 & 0x0F) << 12) | ((s[i+1] & 0x3F) << 6) | (s[i+2] & 0x3F);
i += 3;
} else if ((b0 & 0xF8) == 0xF0) { // 4-byte
if (i + 3 >= s.size()) break;
cp = ((b0 & 0x07) << 18) | ((s[i+1] & 0x3F) << 12) |
((s[i+2] & 0x3F) << 6) | (s[i+3] & 0x3F);
i += 4;
} else {
i += 1; // invalid, skip
continue;
}
if ((cp >= 0x4E00 && cp <= 0x9FFF) ||
(cp >= 0x3400 && cp <= 0x4DBF) ||
(cp >= 0x20000 && cp <= 0x2A6DF)) {
// valid chinese, append original UTF-8 bytes
out.append(s.data() + i - (cp < 0x10000 ? (cp < 0x800 ? 1 : 2) : 3),
cp < 0x80 ? 1 : cp < 0x800 ? 2 : cp < 0x10000 ? 3 : 4);
}
}
return out;
}
为什么不用 std::wstring + iswalpha?
常见误区:把 std::string 强转成 std::wstring,再用 iswalpha 或区域设置(std::locale)判断。这不可靠:
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
立即学习“C++免费学习笔记(深入)”;
-
std::wstring在 Windows 是 UTF-16,在 Linux/macOS 通常是 UCS-4,但原始字符串大概率是 UTF-8,强转导致乱码 -
iswalpha依赖当前 locale,中文 locale 下可能包含全角 ASCII、平假名等,不等于“仅汉字” -
std::iswctype(c, std::wctype("han"))非标准,GCC/Clang 不支持
用 ICU 或 Boost.Locale 的前提和代价
若项目已引入 ICU 库,可用 icu::UnicodeString + uscript_getScript 精确识别汉字脚本:
- 准确率高,支持扩展区、兼容汉字、部首等
- 但 ICU 体积大、编译慢、部署复杂,小工具没必要
- Boost.Locale 同样依赖外部构建,且
boost::locale::is<code>utf8仍需手动查码点
真正要兼顾正确性与轻量,手写 UTF-8 解码 + 码点区间判断仍是首选。别忽略 4 字节字符(扩展 B 区),否则会漏掉“?”“?”这类生僻字。

















