字符编码是什么
举个具体例子:字符『A』的ASCII编号是65(十进制),二进制是 01000001。当程序说「把这个字节当成字符显示」时,计算机会查ASCII表,65对应『A』,于是屏幕上出现A。
问题来了:不同国家有不同的字符,ASCII的128个位置远远不够。于是各国开始搞自己的编码标准:
- 中国:GB2312 → GBK → GB18030
- 日本:Shift-JIS
- 韩国:EUC-KR
- 台湾:Big5
这就导致一个文件在中国电脑上打开正常,在日本电脑上打开就乱码了。Unicode就是为了解决这个问题而生的——一个字符集覆盖全人类文字。
UTF-8 编码原理(重点)
UTF-8是变长编码,用1-4个字节表示一个Unicode字符:
| Unicode范围 | UTF-8字节数 | 二进制格式 | 示例 |
|---|---|---|---|
| U+0000~U+007F | 1字节 | 0xxxxxxx | ASCII字符(A、1) |
| U+0080~U+07FF | 2字节 | 110xxxxx 10xxxxxx | 部分欧洲字符 |
| U+0800~U+FFFF | 3字节 | 1110xxxx 10xxxxxx 10xxxxxx | 中文、日文(大部分) |
| U+10000以上 | 4字节 | 11110xxx 10xxxxxx ... | emoji、生僻汉字 |
这就是为什么中文在UTF-8里占3个字节,而英文只占1个。这个设计很聪明:ASCII字符在UTF-8里和ASCII编码完全一样,所以UTF-8完全兼容ASCII。
乱码问题排查清单
- 检查文件本身编码:用VS Code打开,右下角会显示文件编码,点击可以转换
- 检查HTTP响应头:确保有
Content-Type: text/html; charset=utf-8 - 检查HTML head:确保有
<meta charset="UTF-8"> - 检查数据库:MySQL要确认表/字段的字符集是
utf8mb4(不是utf8) - 检查代码文件编码:Python文件开头加
# -*- coding: utf-8 -*-,JavaScript文件保存为UTF-8
常见编码相关工具
| 工具 | 用途 |
|---|---|
| Base64 编码 | 把二进制数据(图片等)变成可打印ASCII字符 |
| URL 编码 | 把特殊字符(空格、中文)转成 %XX 格式 |
| HTML 实体编码 | 把 < 转成 <(防止XSS和显示问题) |
Python 3 的字符编码处理
# Python 3 的 str 是 Unicode,bytes 是字节串
text = "你好" # str 类型(Unicode)
data = text.encode("utf-8") # 编码成 bytes
text2 = data.decode("utf-8") # 解码回 str
# 文件读写要指定编码
with open("file.txt", "r", encoding="utf-8") as f:
content = f.read()
# 错误做法:不指定编码(用系统默认,Windows是GBK)
with open("file.txt", "r") as f: # 可能乱码
content = f.read()
常见问题 FAQ
MySQL 的 utf8 有什么坑?
MySQL的 utf8 只支持最多3字节,emoji(4字节)存不进去,会报错 Incorrect string value。用 utf8mb4 替代,它是真正的UTF-8。这个坑让无数开发者掉进去过。
Windows 记事本的「带有 BOM 的 UTF-8」是什么?
BOM(Byte Order Mark)是文件开头的几个字节(EF BB BF),用来标记这是UTF-8文件。标准UTF-8不需要BOM,但Windows记事本默认加BOM。有些Linux工具(如gcc、Python解释器)不认识BOM,会导致奇怪的错误。建议保存时选「UTF-8 无 BOM」。
emoji 在数据库里怎么存?
emoji是4字节UTF-8字符,需要数据库字段支持utf8mb4。MySQL需要:1. 数据库/表/字段字符集设为 utf8mb4;2. 连接时也指定 utf8mb4(JDBC URL里加 characterEncoding=utf8mb4)。