CHAR_LENGTH()和LENGTH()的区别

本文介绍了MySQL中用于计算字符串长度的两种方法:LENGTH() 和 CHAR_LENGTH()。LENGTH() 按照字节计数,适用于不同字符集编码如UTF-8等;而CHAR_LENGTH()则按字符计数,对所有字符包括多字节字符统一处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

mysql中计算字符串长度有两个函数分别为char_length和length。char_length函数可以计算unicode字符,包括中文等字符集的长度,而length函数用来计算普通字符的长度,他会把一个中文字符的长度按照设置的对应的字符集计算为2或3。

    无论是LENGTH()还是CHAR_LENGTH()都是为了统计字符串的长度。只不过,LENGTH()是按照字节来统计的,CHAR_LENGTH()是按照字符来统计的。例如:一个包含5个字符且每个字符占两个字节(比如汉字)的字符串而言,LENGTH()返回长度10,CHAR_LENGTH()返回长度是5;如果对于单字节的字符,则两者返回结果相同。

一、char_length('string')/char_length(column_name)

1、返回值为字符串string或者对应字段长度,长度的单位为字符,一个多字节字符(例如,汉字)算作一个单字符;

2、不管汉字还是数字或者是字母都算是一个字符;

3、任何编码下,多字节字符都算是一个字符; 


二、length('string')/length(column_name)

1、utf8字符集编码下,一个汉字是算三个字符,一个数字或字母算一个字符。

2、其他编码下,一个汉字算两个字符, 一个数字或字母算一个字符。


参考:https://www.cnblogs.com/mucheng/p/7742691.html


<think>UTF-8编码中,一个字符(Unicode码点)可以由1到4个字节组成,而不仅仅是3个字节。具体字节数取决于字符的Unicode码点范围。 UTF-8编码规则: 1. 单字节字符:0xxxxxxx(ASCII字符,范围U+0000到U+007F) 2. 双字节字符:110xxxxx 10xxxxxx(范围U+0080到U+07FF) 3. 三字节字符:1110xxxx 10xxxxxx 10xxxxxx(范围U+0800到U+FFFF,包括常用汉字) 4. 四字节字符:11110xxx 10xxxxxx 10xxxxxx 10xxxxxx(范围U+10000到U+10FFFF,如表情符号) 因此,UTF-8字符的字节数可以是1、2、3或4个字节。 下面是一个C++函数,用于计算UTF-8字符串中的字符数(即码点数量): ```cpp #include <iostream> #include <string> #include <cstddef> // 计算UTF-8字符串中的字符数量(码点数量) size_t count_utf8_chars(const std::string& utf8_str) { size_t char_count = 0; for (size_t i = 0; i < utf8_str.length(); ) { unsigned char c = static_cast<unsigned char>(utf8_str[i]); if (c < 0x80) { // 单字节字符 (0xxxxxxx) i += 1; } else if ((c & 0xE0) == 0xC0) { // 双字节字符 (110xxxxx) i += 2; } else if ((c & 0xF0) == 0xE0) { // 三字节字符 (1110xxxx) i += 3; } else if ((c & 0xF8) == 0xF0) { // 四字节字符 (11110xxx) i += 4; } else { // 非法字节,跳过(或抛出异常) i += 1; } char_count++; } return char_count; } int main() { std::string str = "Hello 世界! 🌍"; // 注意:字符串字面量需要确保编译器以UTF-8编码保存文件 // 或者使用u8前缀(C++11及以上) // std::string str = u8"Hello 世界! 🌍"; std::cout << "字节数: " << str.length() << std::endl; std::cout << "字符数: " << count_utf8_chars(str) << std::endl; return 0; } ``` 输出示例: ``` 字节数: 19 字符数: 11 ``` 解释: - "Hello ":6个字符(每个1字节,共6字节) - "世界":2个字符(每个3字节,共6字节) - "! ":2个字符(每个1字节,共2字节) - "🌍":1个字符(4字节) - 总计:6+2+2+1=11个字符,6+6+2+4=18字节(实际19是因为字符串末尾有null终止符?但这里计算的是字符串内容长度,不包括null。注意:字符串中可能包含空格,这里统计的是可见字符,但函数统计的是码点数量,包括空格标点) 注意:上面的字符串"Hello 世界! 🌍"中,空格标点都是单字节。所以实际字节数计算: H e l l o 世 界 ! 🌍 1 1 1 1 1 1 3 3 1 1 4 -> 1*6 + 3*2 + 1*2 + 4 = 6+6+2+4=18字节 但为什么输出19?可能是因为字符串中有一个额外的空格?或者统计有误?实际上,字符串"Hello 世界! 🌍"的组成: 'H','e','l','l','o',' ','世','界','!',' ','🌍' -> 11个字符 字节:1+1+1+1+1+1+3+3+1+1+4=18 所以输出字节数18,但实际运行中,如果字符串是18字节,那么str.length()返回18。 在C++中,如果源代码文件保存为UTF-8,那么字符串字面量中的非ASCII字符会以多字节存储。使用u8前缀(C++11)可以确保字符串字面量是UTF-8编码。 重要注意事项: 1. 函数`count_utf8_chars`只计算有效的UTF-8字符(码点)数量,不验证字节序列的有效性。如果字符串包含无效的UTF-8序列,结果可能不准确。 2. 对于包含组合字符(如带重音符号的字符)的字符串,这个函数返回的是码点数量,而不是可见字符数量(字形簇)。例如,é可以用一个码点(U+00E9)表示,也可以用两个码点(e + 重音符)表示,后者会被计为两个字符。 如果需要更严格的处理,可以结合验证: ```cpp // 带验证的UTF-8字符计数 size_t count_utf8_chars_checked(const std::string& utf8_str) { size_t char_count = 0; for (size_t i = 0; i < utf8_str.length(); ) { unsigned char c = static_cast<unsigned char>(utf8_str[i]); size_t len = 0; if (c < 0x80) { len = 1; } else if ((c & 0xE0) == 0xC0) { len = 2; } else if ((c & 0xF0) == 0xE0) { len = 3; } else if ((c & 0xF8) == 0xF0) { len = 4; } else { // 非法首字节,跳过这一个字节 i++; continue; } // 检查是否有足够的字节 if (i + len > utf8_str.length()) { // 不完整的字符,跳过剩余部分 break; } // 检查后续字节是否有效(10xxxxxx) bool valid = true; for (size_t j = 1; j < len; j++) { unsigned char next = static_cast<unsigned char>(utf8_str[i+j]); if ((next & 0xC0) != 0x80) { valid = false; break; } } if (valid) { i += len; char_count++; } else { // 无效序列,跳过首字节继续 i++; } } return char_count; } ``` 总结: - UTF-8字符长度可以是1、2、3或4个字节。 - 不能假设所有字符都是3个字节,特别是对于ASCII字符(1字节)表情符号(4字节)。 - 在C++中处理UTF-8字符串时,应使用专门的方法来遍历字符,而不是按字节遍历。 §§相关问题§§: 1. 在C++中如何正确地遍历UTF-8字符串的每个字符? 2. 如何将UTF-8字符串转换为大写(考虑Unicode规则)? 3. C++标准库对Unicode的支持有哪些? 4. 如何处理UTF-8字符串的子串操作(避免截断字符)?</think># UTF-8字符编码的字节长度解析 UTF-8编码中,一个字符(Unicode码点)的字节长度不是固定的3字节,而是根据字符的Unicode码点值在1到4字节之间变化。以下是详细解释: ## UTF-8编码规则 | 字节数 | 码点范围 | 二进制模式 | 示例字符 | |--------|---------------------|--------------------------------|----------| | 1字节 | U+0000 到 U+007F | `0xxxxxxx` | A, 7, ! | | 2字节 | U+0080 到 U+07FF | `110xxxxx 10xxxxxx` | é, ß | | 3字节 | U+0800 到 U+FFFF | `1110xxxx 10xxxxxx 10xxxxxx` | 中, 文, 日 | | 4字节 | U+10000 到 U+10FFFF | `11110xxx 10xxxxxx 10xxxxxx 10xxxxxx` | 😊, 𠮷 | ## 验证UTF-8字符长度的C++代码 ```cpp #include <iostream> #include <string> #include <cctype> #include <iomanip> #include <vector> // 获取UTF-8字符的字节长度 size_t getUtf8CharLength(char first_byte) { unsigned char c = static_cast<unsigned char>(first_byte); if ((c & 0x80) == 0x00) { // 0xxxxxxx return 1; } else if ((c & 0xE0) == 0xC0) { // 110xxxxx return 2; } else if ((c & 0xF0) == 0xE0) { // 1110xxxx return 3; } else if ((c & 0xF8) == 0xF0) { // 11110xxx return 4; } return 0; // 无效的UTF-8起始字节 } // 打印字符的UTF-8编码详情 void printUtf8CharInfo(const std::string& str, size_t start_index) { size_t len = getUtf8CharLength(str[start_index]); if (len == 0 || start_index + len > str.length()) { std::cout << "无效的UTF-8字符\n"; return; } std::cout << "字符: "; for (size_t i = 0; i < len; i++) { std::cout << str[start_index + i]; } std::cout << "\n字节长度: " << len << "\n字节序列: "; for (size_t i = 0; i < len; i++) { std::cout << "0x" << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(static_cast<unsigned char>(str[start_index + i])) << " "; } // 计算Unicode码点 uint32_t code_point = 0; if (len == 1) { code_point = static_cast<unsigned char>(str[start_index]); } else { code_point = static_cast<unsigned char>(str[start_index]) & (0xFF >> (len + 1)); for (size_t i = 1; i < len; i++) { code_point = (code_point << 6) | (static_cast<unsigned char>(str[start_index + i]) & 0x3F); } } std::cout << "\nUnicode码点: U+" << std::hex << std::uppercase << code_point << "\n\n"; } int main() { // 使用u8前缀确保UTF-8编码(C++11及以上) std::string text = u8"A é 中 😊"; std::cout << "分析字符串: " << text << "\n\n"; for (size_t i = 0; i < text.length(); ) { size_t char_len = getUtf8CharLength(text[i]); if (char_len == 0) { std::cerr << "在位置 " << i << " 发现无效UTF-8字符\n"; break; } printUtf8CharInfo(text, i); i += char_len; } return 0; } ``` ## 程序输出示例 ``` 分析字符串: A é 中 😊 字符: A 字节长度: 1 字节序列: 0x41 Unicode码点: U+41 字符: 字节长度: 1 字节序列: 0x20 Unicode码点: U+20 字符: é 字节长度: 2 字节序列: 0xC3 0xA9 Unicode码点: U+E9 字符: 字节长度: 1 字节序列: 0x20 Unicode码点: U+20 字符: 中 字节长度: 3 字节序列: 0xE4 0xB8 0xAD Unicode码点: U+4E2D 字符: 字节长度: 1 字节序列: 0x20 Unicode码点: U+20 字符: 😊 字节长度: 4 字节序列: 0xF0 0x9F 0x98 0x8A Unicode码点: U+1F60A ``` ## 关键概念解释 1. **可变长度编码**: - UTF-8使用1-4字节表示字符 - ASCII字符(U+0000到U+007F)保持单字节不变 - 非ASCII字符使用多字节序列 2. **编码结构**: - 首字节包含长度信息(高位1的数量表示总字节数) - 后续字节以`10`开头 - 这种设计使UTF-8具有自同步能力 3. **3字节字符的常见性**: - 大多数非拉丁文字符(如中文、日文、韩文)使用3字节 - 基本多文种平面(BMP)字符(U+0000到U+FFFF)使用3字节或更少 - 但这不是固定规则,许多字符使用更少字节 4. **4字节字符**: - 用于辅助平面字符(U+10000到U+10FFFF) - 包括表情符号、历史文字、特殊符号等 - 在现代应用中越来越常见 ## 处理UTF-8字符串的注意事项 1. **不要假设字符长度**: ```cpp // 错误:假设所有字符都是3字节 for (int i = 0; i < str.length(); i += 3) { // 会错误处理1字节、2字节4字节字符 } // 正确:使用字符感知的遍历 for (size_t i = 0; i < str.length(); ) { size_t char_len = getUtf8CharLength(str[i]); // 处理从i开始的char_len个字节 i += char_len; } ``` 2. **标准库限制**: - C++标准库不直接支持UTF-8字符操作 - `std::string`按字节操作,而非字符 - 需要第三方库(如ICU)或自定义函数处理Unicode 3. **计算字符数量**: ```cpp size_t countUtf8Chars(const std::string& utf8_str) { size_t count = 0; for (size_t i = 0; i < utf8_str.length(); ) { size_t len = getUtf8CharLength(utf8_str[i]); if (len == 0) break; // 无效字符 i += len; count++; } return count; } ``` ## 总结 UTF-8字符的字节长度不是固定的3字节: - ASCII字符:1字节 - 西欧语言字符:通常2字节 - 中文、日文、韩文字符:通常3字节 - 表情符号特殊字符:4字节 在C++中正确处理UTF-8需要: 1. 理解UTF-8编码原理 2. 使用字符感知的函数处理字符串 3. 避免基于固定字节长度的假设 4. 考虑使用Unicode处理库进行复杂操作
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值