在C++开发中,判断字符串是否全为中文字符是文本校验的常见需求,比如用户昵称、地址输入等场景都需要做这类校验。UTF-8是目前最常用的中文编码格式,了解它的编码规则是实现判断功能的基础。

UTF-8编码下中文字符的范围特征
UTF-8是一种变长编码,不同范围的字符占用不同字节数:
- 单字节字符:0x00~0x7F,对应ASCII字符,不包含中文
- 双字节字符:0xC0~0xDF开头,第二个字节范围0x80~0xBF,不包含常用中文
- 三字节字符:0xE0~0xEF开头,第二个字节范围0x80~0xBF,第三个字节范围0x80~0xBF,常用中文字符大多在这个范围
- 四字节及以上字符:0xF0及以上开头,对应生僻字、emoji等,不属于常规中文字符
常规中文字符的Unicode范围是U+4E00到U+9FFF,转换为UTF-8编码后,对应的字节范围是:第一个字节0xE4~0xE9,第二个字节0x80~0xBF,第三个字节0x80~0xBF。不过更严谨的方式是先解析出UTF-8对应的Unicode码点,再判断是否在中文范围内。
核心实现逻辑
判断流程可以分为三步:
- 遍历字符串的每个字节,解析出完整的UTF-8字符
- 将UTF-8字符转换为对应的Unicode码点
- 判断码点是否在
U+4E00到U+9FFF的中文范围内
需要注意处理不完整的UTF-8字节序列,避免越界访问。
完整代码示例
以下是完整的判断函数实现,包含UTF-8解析和中文范围校验:
#include <string>
#include <cstdint>
// 判断单个UTF-8字符是否为中文字符
// 参数:str为字符串起始位置,len为剩余字符串长度,char_len为输出参数,返回解析到的字符字节数,若为0表示无效序列
// 返回对应的Unicode码点,若为0xFFFFFFFF表示解析失败
static uint32_t get_utf8_codepoint(const char* str, size_t len, size_t& char_len) {
char_len = 0;
if (len == 0) return 0xFFFFFFFF;
unsigned char c = static_cast<unsigned char>(str[0]);
if (c < 0x80) {
// 单字节ASCII字符
char_len = 1;
return c;
} else if ((c >= 0xC0) && (c <= 0xDF)) {
// 双字节字符
if (len < 2) return 0xFFFFFFFF;
char_len = 2;
uint32_t codepoint = ((c & 0x1F) << 6) | (static_cast<unsigned char>(str[1]) & 0x3F);
return codepoint;
} else if ((c >= 0xE0) && (c <= 0xEF)) {
// 三字节字符
if (len < 3) return 0xFFFFFFFF;
char_len = 3;
uint32_t codepoint = ((c & 0x0F) << 12) | ((static_cast<unsigned char>(str[1]) & 0x3F) << 6) | (static_cast<unsigned char>(str[2]) & 0x3F);
return codepoint;
} else if ((c >= 0xF0) && (c <= 0xF7)) {
// 四字节字符
if (len < 4) return 0xFFFFFFFF;
char_len = 4;
uint32_t codepoint = ((c & 0x07) << 18) | ((static_cast<unsigned char>(str[1]) & 0x3F) << 12) | ((static_cast<unsigned char>(str[2]) & 0x3F) << 6) | (static_cast<unsigned char>(str[3]) & 0x3F);
return codepoint;
}
// 无效的UTF-8起始字节
return 0xFFFFFFFF;
}
// 判断字符串是否全为中文字符
bool is_all_chinese(const std::string& str) {
size_t pos = 0;
size_t len = str.size();
while (pos < len) {
size_t char_len = 0;
uint32_t codepoint = get_utf8_codepoint(str.c_str() + pos, len - pos, char_len);
// 解析失败或者字符不是中文范围
if (codepoint == 0xFFFFFFFF || char_len == 0) {
return false;
}
// 中文Unicode范围 U+4E00 到 U+9FFF
if (codepoint < 0x4E00 || codepoint > 0x9FFF) {
return false;
}
pos += char_len;
}
// 空字符串返回false,可根据需求调整
return pos > 0;
}
测试验证
可以编写简单的测试代码验证函数正确性:
#include <iostream>
int main() {
std::string test1 = "中文测试";
std::string test2 = "中文abc";
std::string test3 = "emoji😊";
std::string test4 = "混合123中文";
std::cout << "测试1 中文测试: " << (is_all_chinese(test1) ? "是" : "否") << std::endl;
std::cout << "测试2 中文abc: " << (is_all_chinese(test2) ? "是" : "否") << std::endl;
std::cout << "测试3 emoji😊: " << (is_all_chinese(test3) ? "是" : "否") << std::endl;
std::cout << "测试4 混合123中文: " << (is_all_chinese(test4) ? "是" : "否") << std::endl;
return 0;
}
上述测试代码的输出结果应该是:测试1返回是,其余三个返回否,符合预期判断逻辑。
注意事项
- 如果字符串包含生僻中文字符,比如
U+9FA5之后的扩展汉字,需要根据实际需求调整Unicode范围,比如扩展A区是U+3400到U+4DBF - 输入的字符串必须是合法的UTF-8编码,如果是其他编码比如GBK,需要先转换为UTF-8再做判断
- 空字符串的判断逻辑可以根据业务需求调整,上述代码中空字符串返回false