utf8编码cpp string的计算字符和字节数

⌚Time: 2025-11-22 00:38:00

👨‍💻Author: Jack Ge

我在使用下面的sqlite3语句进行更新数据库的cpp代码。在处理中文时出现错误

const char *sql = "UPDATE share_map SET target_path = ? || SUBSTR(target_path, ?) WHERE target_path LIKE ? OR target_path = ?;";

...

int old_path_length = pathstr.length();
sqlite3_bind_int(stmt, 2, old_path_length+1);//从length+1截取
        

原因是使用的sqlite3的SUBSTR函数是根据字符位置截取的。而std::string length()函数返回的是字节数。对于UTF8编码的字符,每个字符可能是1个,也可能是多个字节,这就造成了不统一,错误。

比如"abc中文"这个字符串,utf8对于汉字是3字节1字符,英文字母是1字节1字符,所以length()函数会返回9,实际上期望的是5。


解决办法是

A. 把字符串绑定到sqlite3语句,调用sqlite3自己的函数来计算字符数。

B. 自己手动计算utf8字符数

B办法我使用

代码是

size_t utf8_strlen(const std::string& str) {
    size_t len = 0;
    for (unsigned char c : str) {
        if ((c & 0xC0) != 0x80) {  // 统计UTF-8字符起始字节
            ++len;
        }
    }
    return len;
}

这个函数通过检测UTF-8编码的字节特征来统计字符数,原理是续字节识别。

UTF-8编码规则

UTF-8使用1-4个字节表示一个字符,编码规则如下:

字符类型 字节1范围 字节2范围 字节3范围 字节4范围 总字节数
单字节字符 0x00-0x7F - - - 1
双字节字符 0xC0-0xDF 0x80-0xBF - - 2
三字节字符 0xE0-0xEF 0x80-0xBF 0x80-0xBF - 3
四字节字符 0xF0-0xF7 0x80-0xBF 0x80-0xBF 0x80-0xBF 4

关键原理:

在UTF-8中:

判断条件分解:


所以将utf8_strlen替换length函数就行了


int old_path_length = utf8_strlen(pathstr);
sqlite3_bind_int(stmt, 2, old_path_length+1);//从length+1截取