一个汉字三种编码:UTF-8、GBK、UTF-16 逐字节对比实测

举报
deli007 发表于 2026/10/13 21:41:53 2026/10/13
【摘要】 一个汉字三种编码:UTF-8、GBK、UTF-16 逐字节对比实测

图 1:字符编码实验室首屏。输入框里是默认文本「汉字A😀」,下面逐字符列出 Unicode 码位、UTF-8 字节、UTF-16 码元和 GBK 字节,emoji 那一行的 GBK 一栏写着 N/A

「汉」在 UTF-8 里是 E6 B1 89,在 GBK 里是 BA BA,在 UTF-16LE 里是 49 6C。

同一个字,三种编码,分别是 3 字节、2 字节、2 字节。

我把这三个数字摊在同一张表里对了一遍,谁多一个字节、谁换了字节序,一眼可见。

emoji 的差别更大:😀 在 UTF-8 里占 4 个字节,在 UTF-16 里也是 4 个,GBK 干脆编不出来,页面上标成 N/A。

乱码也不是文件坏了,是拿另一种编码去读了同一串字节。

成品是一个单文件 index.html,双击就能跑,不联网,不引第三方库。

案例目录在这里,下载下来直接打开:

https://atomgit.com/deli007/demo_park/tree/main/codearts-unicode-encoding-lab

一、先把默认文本的字节摊开

字符 Unicode 码位 UTF-8 字节 UTF-16LE 码元 GBK 字节
汉 U+6C49 E6 B1 89 49 6C BA BA
字 U+5B57 E5 AD 97 57 5B D7 D6
A U+0041 41 41 00 41
😀 U+1F600 F0 9F 98 80 3D D8 00 DE 不支持

表里每一格都是页面打开时当场算的,不是我抄的。

汉字在 UTF-8 里占 3 字节,这就是「一个汉字三个字节」这句话的出处。

GBK 只占 2 字节,这也是老项目里中文文本普遍更小的原因。

字母 A 在三种编码里都是自己,UTF-16 为了凑对齐,后面补了一个 00。

emoji 那行最扎眼,GBK 那一格直接写着不支持。

二、为什么值得做这个页面

乱码是中文开发者绕不开的事,但很多人停在了「编码不统一」这句结论上。

具体是哪几个字节、被谁读成了什么、为什么正好是「锟斤拷」,很少有人讲透。

我回想了一下自己踩坑的经历:这个问题在三个不同项目里各出现过一次,每次都靠搜索救回来。

所以它不是一个看完就忘的演示,而是有明确检索词的东西:UTF-8、GBK、乱码、UTF-16。

页面要做的事很窄,给我一串字符,告诉我它在四种编码下的真实字节。

窄的好处是每一项都能验。

图 2:把输入换成 𠮷、中、A。𠮷 的码位是 U+20BB7,UTF-8 要 4 字节、UTF-16 是 2 码元,GBK 同样不支持;下面切到 UTF-16BE 标签页,字节序列是 D8 42 DF B7 4E 2D 00 41

三、怎么做:三种编码,三条不同的路

UTF-8 和 UTF-16 在浏览器里是原生能力,直接调就行。

UTF-8 用 TextEncoder 一行拿到字节数组。

UTF-16LE 和 UTF-16BE 用 charCodeAt 把每个码元拆成高低字节,BE 只是把这两个字节换个顺序。

麻烦的是 GBK,浏览器只给了 TextDecoder,负责解码,没有对应的编码器。

没有编码器,就得自己造一张反查表。

我的做法是让解码器反过来工作:首字节从 0x81 枚举到 0xFE,次字节从 0x40 枚举到 0xFE,跳过 0x7F。

每组两字节丢进 TextDecoder(‘gbk’) 解一次,解得出的字符就跟这两个字节绑在一起。

一共试了 23940 组,建出 24067 条映射,其中 128 条来自 ASCII 单字节。

我在页面上掐了时间,整张表建完 18.5 毫秒,再刷一遍是 17.7 毫秒,映射条数两次都是 24067。

这个数字是页面上真跑出来的,不是估的。

四、乱码复现:把两次错误解码摆在同一屏

图 3:乱码复现面板。左栏把「汉字A😀」的 UTF-8 字节 E6 B1 89 E5 AD 97 41 F0 9F 98 80 按 GBK 解成「姹夊瓧A馃榾」,右栏把 GBK 字节 BA BA D7 D6 41 3F 按 UTF-8 解成四个替换字符加 A?,两栏下面都写了原因

左栏的原始字节是 E6 B1 89 E5 AD 97 41 F0 9F 98 80,按 GBK 读出来是「姹夊瓧A馃榾」。

右栏的原始字节是 BA BA D7 D6 41 3F,按 UTF-8 读出来是四个替换字符加一个 A?。

同一串「汉字A😀」,换个读法就成了两个不同的怪东西。

「锟斤拷」的来历我也在页面上验了一遍。

把两个 UTF-8 的替换字符 0xEF 0xBF 0xBD 连起来,用 GBK 解,正好是「锟斤拷」。

单个 EF BF BD 解出来只有一个「锟」加半个乱码,两个连在一起才凑齐这三个字。

这也是老文章里的乱码经常成对出现的原因。

五、验证与踩坑:自检 12 条全绿,UTF-16BE 解码却是崩的

页面底部有自检区,把每种编码的期望字节写成断言,跑完显示通过条数。

图 4:自检面板。14 条断言逐条列出期望值和实际值,最后一行写着自检结果 14/14 条通过

交付过来的时候是 12 条,全绿。

但我在字节解码器里试 UTF-16BE 的时候,它当场就崩了。

输入 4E 2D、选中 UTF-16BE,输出是「❌ 解码失败:e is not defined」。

图 5:修复前的失败现场。解码器里输入 E4 B8 AD、编码选 UTF-16BE,输出是「❌ 解码失败:e is not defined」

原因很小:那个函数的成功分支里写了一句 e.message,而 e 只在 catch 里存在。

成功路径一走就抛 ReferenceError。

更值得记的是它为什么没被自检拦住,12 条断言全是把字符编成字节,没有一条是把字节解回字符。

编解码是对称的东西,只测一半等于没测。

我补了两条解码断言,一条测「中」的 UTF-16BE,一条测「汉」的 GBK,现在自检是 14 条。

第二处是文案错,不改就是误导。

右栏下面原来写着「烫烫烫来自 GBK 编码的汉字被 UTF-8 错误解码」,这句话是错的。

我在页面上试了原始字节:CC CC 用 GBK 解是「烫」,CD CD 用 GBK 解是「屯」。

所以「烫烫烫」来自调试器把未初始化内存填成 0xCC,跟「GBK 汉字被 UTF-8 解码」没关系。

我把这段文案改成了正确说法,改完又跑了一遍确认数字对得上。

第三处是解码器对非法输入太宽容。

原来输入 ZZ 11,它把 Z 悄悄扔掉,解出一个控制字符 0x11,看起来像正常结果。

现在它会直接报「❌ 含非十六进制字符:ZZ」,十六进制位数是奇数时也会提示补全。

三处改完刷新,自检 14/14,UTF-16BE 解 4E 2D 得到「中」,解 4E 2D 5B 57 得到「中字」。

六、本地复现

把案例目录下载下来,随便起一个静态服务:

cd codearts-unicode-encoding-lab
python -m http.server 8000

浏览器打开 http://localhost:8000/index.html 就能看到跟截图一样的页面。

不起服务直接双击 index.html 也可以。

亲手点三下:先看默认文本的字节表,再把输入换成 𠮷 或 😀 看 N/A 那一格,最后去解码器里贴一段非法十六进制,看它怎么报错。

七、准备环境:打开码道 Web 版

浏览器打开码道 Web 版:https://devcloud.cn-north-4.huaweicloud.com/chat?source=dmzntgwsf&sourcead=dmzntgwwbwz

登录后在对话框里把需求说清楚就行,不用装软件。

码道有三种使用方式:WebUI 浏览器对话、TUI 终端命令行和桌面 IDE 插件,本文用的是 WebUI。

八、用码道做这个页面的一点体会

需求我一次说完了:四种编码的字节序列、逐字符展开、乱码复现、字节解码器,再加一个自检区。

它一次就给了一个能跑的单文件页面,内置预览里直接能点。

但「能跑」和「对」是两件事。

这三处问题里,最要命的那处在自检全绿的情况下藏得最好。

另外两处是文案和输入校验,都属于不跑一遍就发现不了的。

我的做法是,把自检断言写进需求,交付后自己再逐项点一遍,尤其是编解码这种对称的东西。

让 AI 写代码,验收这一半得自己扛。

九、边界,我写清楚

第一,GBK 映射表是靠 TextDecoder(‘gbk’) 枚举出来的,实测建出 24067 条,覆盖常用汉字够用,但它是按解码结果反推的,不等价于一份权威码表。

第二,页面只处理 GBK,不处理 GB18030,也不处理 Big5 和 Shift-JIS。

第三,emoji 在 GBK 里编不出来,页面统一用 0x3F 问号代替,这是我定的规则,不是标准规定。

第四,自检里的期望值是我手写的,它只能证明代码算出了我预期的东西,证明不了我的预期一定对。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。