UTF-8编码原理详解:字符怎么变成字节

liuzw 39 0

中文字符在文件里到底占几个字节?为什么有时候是3个有时候是2个?为什么同一份文件换个编辑器就乱码?这些问题都指向UTF-8编码原理。按下面步骤把Unicode和UTF-8的关系理清,编码问题基本能自己诊断。

Unicode和UTF-8是什么关系

Unicode是字符集,给全世界每个字符分配一个唯一编号叫码点,比如汉字你对应的码点是U+4F60。但Unicode只规定编号不规定怎么存。UTF-8是Unicode的一种存储实现,把码点转换成字节序列。还有UTF-16、UTF-32等别的实现。所以Unicode是概念层,UTF-8是工程层,这俩不是一回事但常被混用。

第一步:理解UTF-8的变长设计。UTF-8用1到4个字节存一个字符,ASCII字符(码点0到127)用1个字节,和ASCII完全兼容。拉丁字母扩展、希腊字母等用2个字节。中文常用字用3个字节。生僻字和emoji用4个字节。这就是为什么中文字符在UTF-8里占3个字节而不是2个,2个字节是GBK或UTF-16的存法。

第二步:掌握UTF-8的编码规则。每个字节的开头几位指示这个字节的角色。1字节字符以0开头。多字节字符的第一个字节以连续的1开头,1的个数等于总字节数,后面跟个0。后续字节都以10开头。比如3字节字符的第一个字节是1110开头,后两个是10开头。这个设计让解码器能从任意字节判断它是首字节还是续字节,容错性强。

第三步:算出具体编码。以汉字你码点U+4F60为例,4F60的二进制是0100111101100000,共15位。3字节UTF-8能存16位码点,把15位填进去,分成4位6位6位三段,套上1110和10的前缀,得到E4BD A0三个字节。可以用十六进制编辑器打开文件验证,中文你的UTF-8编码就是E4 BD A0。

第四步:理解BOM和字节序。BOM是字节顺序标记,字符U+FEFF。UTF-8没有字节序问题(因为是字节流不是字),所以BOM在UTF-8里没意义,但有些软件会加。UTF-8的BOM是EF BB BF三个字节。这个BOM会导致一些解析器报错,尤其是JSON和XML解析。存文件时选UTF-8无BOM是最稳妥的。

第五步:诊断常见乱码。乱码本质是编码和解码用了不同规则。最典型的是UTF-8存的中文用GBK打开,或反过来。UTF-8中文3字节被GBK按2字节一组读,就会显示成乱码。判断文件是什么编码,看前几个字节:EF BB BF是UTF-8带BOM,FF FE是UTF-16小端,FE FF是UTF-16大端。排除编码问题,统一用UTF-8存一切文件是最佳实践。

几个常被问的问题

【为什么我的中文有时占2字节有时3字节?】占2字节的是GBK或UTF-16编码,占3字节的是UTF-8。同一个字符在不同编码下字节数不同。确认文件用什么编码,字节数才有意义。

【emoji占几个字节?】UTF-8里emoji是4字节,因为它的码点在U+1F000以上。有些老系统或数据库字段用utf8只支持3字节,存emoji会报错,得用utf8mb4。MySQL的utf8mb4才是真正的UTF-8。

【怎么把GBK文件转成UTF-8?】用编辑器打开,另存为时选UTF-8编码。批量转换用iconv命令。注意转完检查有没有乱码,因为GBK有些字符在UTF-8里映射不同。转之前备份原文件。

UTF-8的核心是变长和前缀码设计,理解了码点到字节的映射,编码乱码问题就是送分题。记住ASCII兼容、中文3字节、BOM有害这三条,日常开发能少踩不少坑。

标签: UTF-8 字符编码 Unicode 乱码

抱歉,评论功能暂时关闭!