可变长编码
不同字符使用不同字节数的编码方式。UTF-8 (1-4 字节) 和 Shift_JIS (1-2 字节) 是典型代表,通过用较短的字节序列表示高频字符来提高效率。
可变长编码 (variable-length encoding) 是指不将所有字符用相同的字节数表示,而是根据字符分配不同字节数的编码方式。其反义词是定长编码,UTF-32 (所有字符均为 4 字节) 和 ASCII (所有字符均为 1 字节) 属于定长编码。
可变长编码最大的优势在于空间效率。UTF-8 中,ASCII 字符 (英文字母、数字、符号) 仅占 1 字节,中文汉字占 3 字节,部分 emoji 占 4 字节。在以英文内容为主的 Web 上,与 UTF-32 相比可节省 75% 的数据量。即使是中文文本,UTF-8 的 3 字节/字符相比 UTF-32 的 4 字节/字符也能节省 25%。
UTF-8 的可变长设计非常精巧。仅通过查看首字节的位模式,就能判断该字符由几个字节组成:1 字节字符为 0xxxxxxx,2 字节字符为 110xxxxx 10xxxxxx,3 字节字符为 1110xxxx 10xxxxxx 10xxxxxx,4 字节字符为 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx。这种自同步特性使得即使从字节序列的中间开始读取,也能正确检测到字符边界。
Shift_JIS 也是可变长编码。ASCII 兼容字符和半角片假名占 1 字节,汉字和平假名占 2 字节。但 Shift_JIS 不具备 UTF-8 那样的自同步性,从字节序列中间开始读取时可能混淆第一字节和第二字节。这一设计缺陷使得 Shift_JIS 的文本处理更加复杂。类似地,中文的 GBK 编码也是可变长的 (ASCII 为 1 字节,汉字为 2 字节),同样存在自同步性不足的问题。
可变长编码最大的陷阱在于「字符数」与「字节数」不一致。UTF-8 中,「Hello」是 5 字节 (5 个字符),「你好世界啊」是 15 字节 (5 个字符)。要访问字符串中第 n 个字符,必须从头逐一计算字节数,无法像定长编码那样通过简单的乘法直接定位。这会影响编程语言中字符串操作的性能。
在数据库和文件系统的容量规划中,必须正确理解可变长编码的特性。MySQL 的 VARCHAR(255) 在 UTF-8 (utf8mb4) 下最多存储 255 个字符,但最大字节数可达 1,020 字节 (255 x 4)。存储容量的估算应基于字节数而非字符数,否则会与实际情况产生偏差。