← 全部文章 计算机基础

字符编码:ASCII、GBK 与 Unicode

2022 年 7 月 4 日 · 3 分钟读完

目录
  1. 字符、字符集、编码方式
  2. 常见字符集
  3. Unicode 的三种编码方式
  4. UTF-32
  5. UTF-16
  6. UTF-8
  7. 字节序:大端和小端
  8. 怎么认出文件的编码:BOM
  9. ASCII 码表
  10. 延伸

经常遇到编码问题绕来绕去,决定好好学一遍。

字符、字符集、编码方式

  1. 字符:抽象的最小文本单位,只代表一个符号,没有固定的值。「A」「€」「中」都是字符。
  2. 字符集:符号和数字的对应表。它规定了 21475(十六进制 53E3)是「口」。ASCII、GB2312、Unicode 都是字符集。
  3. 编码方式:同样是 21475 这个数,存成 口 还是 %E5%8F%A3(UTF-8 的三个字节),由编码方式决定。UTF-8 是编码方式,不是字符集。

常见字符集

中文字符集的包含关系:

字符集 用途 长度 范围或容量
ASCII 英文 7 位,128 个字符 00 ~ 7F
扩展 ASCII 西欧语言 8 位,256 个字符 00 ~ FF
ISO-8859-1 西欧、希腊语等,兼容 ASCII 8 位 00 ~ FF
GB2312 简体中文,兼容 ASCII 2 字节 7445 个符号,含 6763 个汉字,高低字节都在 A1 ~ FE
BIG5 繁体中文 2 字节 13053 个汉字
GBK GB2312 的扩展,加入繁体 2 字节 21886 个字符,高字节 81 ~ FE,低字节 40 ~ FE
GB18030 兼容 GBK,覆盖少数民族文字、日文、韩文 1、2、4 字节变长 可以表示全部 Unicode 字符
Unicode 全世界的文字统一编号 由 UTF-8/16/32 决定 0 ~ 10FFFF,约 111 万个码位

Unicode 的三种编码方式

UTF-32

固定 4 个字节,直接存 Unicode 编号,不需要转换。省事但费空间。

UTF-16

最初用 2 个字节,例如「我」的编号是 25105(6211),UTF-16 存成 0110 0010 0001 0001。

2 个字节最多到 FFFF,不够覆盖到 10FFFF,所以超出的部分用 4 个字节(代理对):

编号范围 编号的二进制 UTF-16 字节数
0000 ~ FFFF xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx 2
1 0000 ~ 10 FFFF 先减去 1 0000,剩 20 位 yyyy yyyy yyxx xxxx xxxx 110110yy yyyyyyyy 110111xx xxxxxxxx 4

以 110110 开头的是高位代理,以 110111 开头的是低位代理。为了不和 2 字节的字符冲突,D800 ~ DFFF 这一段在 Unicode 里专门空出来,不分配给任何字符。

UTF-8

UTF-16 不兼容 ASCII,英文也要占 2 个字节,很浪费。于是有了 1 ~ 4 字节变长的 UTF-8:

编号范围 UTF-8 字节格式 有效位数 字节数
0 ~ 7F 0xxx xxxx 7 1
80 ~ 7FF 110x xxxx 10xx xxxx 11 2
800 ~ FFFF 1110 xxxx 10xx xxxx 10xx xxxx 16 3
1 0000 ~ 10 FFFF 1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx 21 4

「我」= 6211 = 0110 0010 0001 0001,落在第三行,把 16 位依次填进 1110 xxxx 10xx xxxx 10xx xxxx:

1110 0110 1000 1000 1001 0001 = E6 88 91

所以常用汉字在 UTF-8 里占 3 个字节,在 GBK 里占 2 个字节。

字节序:大端和小端

UTF-16、UTF-32 一个字符占多个字节,哪个字节在前?这就是字节序。

值 0x12345678         低地址 → 高地址
大端(Big-Endian):    12 34 56 78    高位字节放在低地址
小端(Little-Endian): 78 56 34 12    低位字节放在低地址

在记事本里输入「你」(4F60),存成 UTF-16 小端,60 在前:

改成大端,4F 在前:

怎么认出文件的编码:BOM

Unicode 文件可以在开头放几个字节标明编码,叫 BOM(Byte Order Mark):

编码 BOM
UTF-8 EF BB BF(可有可无)
UTF-16 大端 FE FF
UTF-16 小端 FF FE
UTF-32 大端 00 00 FE FF
UTF-32 小端 FF FE 00 00

GB2312、GBK 没有 BOM,只能靠特征猜:GB2312 一个汉字的高低字节最高位都是 1;GBK 只保证高字节最高位是 1。最高位是 0 的就是 ASCII。

ASCII 码表

来源:菜鸟教程 ASCII 表

几个值得背下来的:'0' 是 48(0x30),'A' 是 65(0x41),'a' 是 97(0x61),大小写正好差 32;回车 \r 是 13,换行 \n 是 10。串口和 PLC 报文里经常能看到它们。

延伸

  • C# 的 string 是 UTF-16:"😀".Length 等于 2,因为表情在 BMP 之外,要用一对代理。按「用户看到的字符」计数要用 StringInfo 或 .NET Core 3.0 起的 Rune。
  • .NET Core 默认不认识 GBK:先 Encoding.RegisterProvider(CodePagesEncodingProvider.Instance),再 Encoding.GetEncoding("GBK")。.NET Framework 不需要这一步。
  • Encoding.UTF8 写文件会带 BOM:老设备或别的语言程序读到开头的 EF BB BF 可能出错,用 new UTF8Encoding(false) 写无 BOM 的 UTF-8。
  • 中文 Windows 的「ANSI」就是 GBK(代码页 936):VS 里中文乱码,多半是源文件和编译器理解的编码不一致,见 VS 里中文乱码;数据库乱码见 上位机写数据库中文乱码。

# 字符编码 # Unicode

原文首发于 blog.csdn.net