乱码的根源:字节与字符的错位
计算机里只有字节(0-255 的数字),"字符"是人类约定俗成的显示规则。编码把字符变成字节,解码把字节还原成字符。一旦"编码用的字符集"和"解码用的字符集"不一致,就会出现乱码。
最常见的例子:UTF-8 编码的中文被当成 GBK 解码,就会出现"锟斤拷";GBK 编码的内容被当成 UTF-8 解码,就会出现"æå¥½"这类拉丁扩展字符。理解了这一点,所有编码问题都有章可循。
URL编码:%20 与 + 的区别
URL 里只允许出现字母、数字和少数符号,中文、空格、特殊字符都必须转成 %XX 形式。例如"你好"的 UTF-8 编码是 6 个字节,URL 编码后变成 %E4%BD%A0%E5%A5%BD。
JavaScript 里有两个容易混淆的函数:encodeURI 保留 URL 结构字符(:/?#[]@ 等),适合编码完整网址;encodeURIComponent 编码得更彻底,适合编码参数值。空格在 query 里既可以是 %20 也可以是 +(表单提交惯例),解析时要两种都兼容。
UTF-8 与 Unicode:码点与字节序列
Unicode 给每个字符分配一个码点(如 U+4F60 是"你"),UTF-8 是码点的一种存储方案:常用汉字占 3 字节,Emoji 占 4 字节,英文占 1 字节,完全兼容 ASCII。
编程语言里的 \u4F60 是 Unicode 转义写法,\uD83D\uDE00 这种成对出现的叫代理对(surrogate pair),用于表示超出 BMP 的 Emoji 字符。前端处理用户昵称、特殊符号时,搞不清码点和代理对就会把 Emoji 切成两半。
在 Unicode 转码页输入任意字符,可以同时看到码点、UTF-8 字节序列和 \u 转义三种表示。
乱码修复:锟斤拷从哪来
"锟斤拷"是 UTF-8 的替换字符(U+FFFD,显示为 �)被 GBK 二次解码的结果——原始字节解码失败被替换成 �(EF BF BD 三个字节),这三个字节在 GBK 里恰好是"锟斤拷"。看到锟斤拷,基本可以断定:原始数据是 UTF-8,某环节用 GBK 解码了。
乱码修复的思路是反向重放:把现在的乱码文本用"错误解码"的字符集编回字节,再用"正确编码"重新解码。本站乱码修复页内置了 UTF-8↔GBK 双向重放,粘贴乱码一键尝试多种组合。
HTML 实体转义
HTML 里 <、& 是语法字符,正文里要显示它们必须写成实体:<、&。实体有两种写法:具名(©)和数字(© 十进制 / © 十六进制),数字实体可以表示任何 Unicode 字符。
防止 XSS 的基本功也是实体转义:用户输入渲染进 HTML 前,至少转义 < > & " ' 五个字符。在 HTML 实体转义页可以双向互转,也支持把整段富文本转成安全的转义版本。