如何统计std::string中的实际字符数(而非字节数)?
如何统计std::string中的实际Unicode字符数(而非字节数)
std::string的size()和length()方法返回的是存储的字节数(即char类型的数量),这是因为std::string本质是字节序列容器,并不感知字符编码。对于UTF-8编码的字符串,像ї这样的Unicode字符会占用2个字节,因此"їa"的size是3,但实际是2个Unicode字符。
要统计实际的Unicode字符数,需要根据UTF-8的编码规则手动遍历字节序列,识别每个Unicode字符的边界。
UTF-8编码规则回顾
UTF-8采用变长编码,每个Unicode字符的字节数规则如下:
- 单字节字符:最高位为0,范围
0x00-0x7F(对应ASCII字符) - 双字节字符:起始字节最高两位为
11,第三位为0,范围0xC0-0xDF;后续字节最高两位为10 - 三字节字符:起始字节最高三位为
111,第四位为0,范围0xE0-0xEF;后续两个字节最高两位为10 - 四字节字符:起始字节最高四位为
1111,第五位为0,范围0xF0-0xF7;后续三个字节最高两位为10
实现统计函数
根据上述规则,可以实现一个函数来统计UTF-8字符串中的Unicode字符数:
#include <string> size_t count_unicode_chars(const std::string& str) { size_t char_count = 0; size_t index = 0; const size_t str_len = str.size(); while (index < str_len) { unsigned char current_byte = static_cast<unsigned char>(str[index]); if (current_byte < 0x80) { // 单字节Unicode字符 ++char_count; ++index; } else if (current_byte < 0xE0) { // 双字节Unicode字符,跳过后续1个续字节 ++char_count; index += 2; } else if (current_byte < 0xF0) { // 三字节Unicode字符,跳过后续2个续字节 ++char_count; index += 3; } else if (current_byte < 0xF8) { // 四字节Unicode字符,跳过后续3个续字节 ++char_count; index += 4; } else { // 无效的UTF-8起始字节,可根据需求处理(此处跳过错误字节) ++index; } } return char_count; } // 测试示例 #include <iostream> int main() { std::string m_string1 {"a"}; std::cout << "m_string1的Unicode字符数:" << count_unicode_chars(m_string1) << "\n"; // 输出1 std::string m_string2 {"їa"}; std::cout << "m_string2的Unicode字符数:" << count_unicode_chars(m_string2) << "\n"; // 输出2 return 0; }
注意事项
- 上述函数假设输入的std::string是合法的UTF-8编码,如果存在无效的编码序列,函数会跳过错误字节,计数结果可能不准确。如果需要严格校验UTF-8合法性,可以在函数中添加额外的校验逻辑(比如检查续字节是否符合
0x80-0xBF范围)。 - 如果你的字符串使用的是其他编码(如UTF-16、GBK等),需要对应调整编码解析逻辑,但std::string通常用于存储UTF-8编码的文本。
- C++20及以后标准中,可使用
std::u8string配合<ranges>和<charconv>库来更便捷地处理Unicode字符,但对于旧标准,手动实现是最直接的解决方案。
内容的提问来源于stack exchange,提问作者jcjuarez
相关产品推荐
相关产品推荐

