安全与面试
十种乱码长相速查表:从问号方块到「锟」字全家桶,对号入座就能修
数优编码
Photo: Grj23, CC0, via Wikimedia Commons
为什么值得背这张表
面试里聊编码原理,候选人能背出 UTF-8 是变长编码的不多,能说清「为什么页面上是一排问号」的更少。乱码其实是编码知识最直观的考试题——每种乱码长相都精确对应一种错误操作。把这张表背熟,排查和面试两头收益。
速查表
| # | 你看到的 | 成因 | 修复思路 |
|---|---|---|---|
| 1 | ??? 或 ????? | 写入时字符无法映射到目标字符集(如 GBK 库收了 Emoji),MySQL 用 ? 填充 | 换 UTF-8(utf8mb4)存储,无法救回原数据 |
| 2 | 方块 □□□ 或豆腐块 | 字体缺字形,数据本身没坏 | 换支持该字符的字体,数据层面无需处理 |
| 3 | 是 这类拉丁扩展字符 | UTF-8 字节被按 Latin-1 解释(经典 mojibake) | text.encode('latin-1').decode('utf-8') 逆变换 |
| 4 | ä½ å¥½ | 同上,UTF-8 被按 Windows-1252 读 | 同上,注意 Windows-1252 有不可逆的映射点 |
| 5 | 锟斤拷 | UTF-8 双重错误:坏字节→U+FFFD→再按 GBK 解码 | 从源头修:找到产生 U+FFFD 的环节,原始数据多半已损 |
| 6 | 烫烫烫 | Windows debug 堆未初始化内存填充 0xCC,按 GBK 显示 | 不是编码问题,是内存问题,查未初始化变量 |
| 7 | 一串 你好 | JSON 序列化时非 ASCII 被转义 | ensure_ascii=False(Python)或用支持 UTF-8 的序列化配置 |
| 8 | & < 满天飞 | HTML 实体被二次转义或未解码 | 一次解码即可,禁止对已解码文本重复 escape |
| 9 | 长串 %E4%BD%A0%E5%A5%BD | URL 百分号编码,不是乱码 | urllib.parse.unquote() / decodeURIComponent() |
| 10 | 中文正常但英文正常中文变宽/错位 | 终端或编辑器把 UTF-8 当成单字节解析 | 检查 locale:export LANG=en_US.UTF-8 |
排查三步法
- 确认数据在哪一环变坏:直接查数据库原始字节(MySQL 用
HEX(col)),如果字节是对的,问题在展示层;字节错了,问题在写入层。 - 识别字节模式:UTF-8 中文每字节高位都是 1(
E4–E9开头常见),GBK 中文以D0–F7开头居多。HEX输出对照一下,就能猜出「原始编码 → 被误读成的编码」。 - 能逆则逆,不能逆就重录:单层 mojibake 可以逆变换救回;出现 U+FFFD 或
?说明信息已永久丢失,只能找原始数据源重新导入。
面试怎么答才加分
被问到「线上出现乱码怎么排查」,别只说「统一用 UTF-8」。好的回答结构是:先区分数据损坏与显示错误,再给出字节级验证手段(HEX),最后按乱码长相定位具体环节——这套流程答出来,面试官基本不会再追问了。
把这张表存到书签里,下次凌晨三点被乱码告警叫醒时,你会感谢现在的自己。