现代字符编码模型

名称 工作 元素 集合 Remark
1 抽象字符表(ACR) 字符 字符集 封闭(ASCII,ISO/IEC 8859) 开放(Unicode)
2 编号字符集(CCS) 逻辑编号 Code Point(码点) Code Space(码点空间) Unicode Scalar Value; 可能一对多,可能使用多个码点组成的码点
3 字符编码方式(CEF) 逻辑编码(储存格式) Code Unit Sequence(码元序列) 编码空间 定长编码空间大小固定,变长编码可增大
4 字符编码模式(CES) 物理编码(序列化格式) 字节序列 储存时的编码;考虑大小端序
5 传输编码语法(TES) 适应性编码处理 映射到受限值域/压缩字节序列;传输时的编码

编码方案

编码模型 类型 年份 ACR CCS CEF CES TES
EBCDIC 1964 字母不连续
ASCII(ISO/IEC 646) 1968 控制字符+英文符号字符 $2^7$ 单字节编码
EASCII 扩展表格符号、计算符号、希腊字母、拉丁符号 $2^8$ 高位1为扩展编码
ISO/IEC 8859 ISO/IEC 8859-n (n=1..16 无12) 扩展:0xA0-0xFF 高位1为扩展编码
ISO/IEC 2022 单/双 编码东亚语言(包括 GB2312) C0,C1;G0,G1,G2,G3+区位码
GB 区位码 国标码 机内码
GB2312(EUC-CN) 1981 3755(一级汉字)+3008(二级汉字)+其它(682) $94\times94$ (+20H,+20H) (+80H,+80H)
GBK 1995 根据 GB13000.1-1993 对 GB2312-1980 的扩展 汉字21003个,符号883个,1894个造字位 高位0x81-0xFE,低位0x40-0xFE
GB18030(-2000/-2005) 2000 完全支持Unicode 最多可定义161万个字符 生僻字4字节
Shift-JIS 日文
Big5 1983 高位0x81-0xFE,低位0x40-0x7E
CJK(CKJ Unified Ideographs) 1993 将起源相同,本义相同,形状一样或稍异的汉字给予同码点值
ANSI 兼容ASCII又互相不兼容的字符编码,微软统称为ANSI编码 需要规定语言 Windows系统中指系统默认编码
ISO/IEC 10646(UCS,GB13000) 1993 与 Unicode 标准在 BMP 上保持一致 $2^31$;码点名称 U+
Unicode 1991/1993 17平面,每个平面$2^{16}$ 1,112,064个码位;U+0000到U+10FFFF UTF(Unicode/UCS Transformation Format)
UTF-8 码元8bit,每个字3码元
UTF-16(UCS-2+代理) 码元16bit,每个字1码元;LE/BE
UTF-32(UCS-4) 码元32bit,每个字1码元;LE/BE

ASCII

  • 0x00-0x1F保留给控制字符
    • 10 0x0A 0101b LF/nl 换行
  • 0x20-0x7F用来表示图形字符
    • 0x30 0
    • 0x41 A
    • 0x61 a

ISO/IEC 8859

  • ISO/IEC 8859-1/2/3/4/9/10/13/14/15/16 (Latin1/2/3/4/5/6/7/8/9(0)/10):收录了西欧/东欧/南欧/北欧/土耳其/…常用字母

ISO/IEC 2202 (ECMA-35)

  • 实例
    • 中国国标GB 2312
    • 日本工业规格JIS X 0202(旧称JIS C 6228)
    • 韩国工业规格KS X 1004(旧称KS C 5620)
  • 转义符串(Escape sequence)
    • 1个“ESC”字符(0x1B),再由两至三个字串组成。此标记代表它后面的字符,属于下表字符集的文字
  • 字符集的控制字符可分为两块:C0,C1
  • 打印(图形)字符分为四块:G0,G1,G2,G3
  • 单字节的编码空间为94
  • 双字节的编码空间(区位码)为94x94

EUC (Extended Unix Code)

  • 实现 ISO/IEC 2202
  • 四个码集
    • 0: C0 + G0
    • 1,2,3: G1
      • 1: 0xA1-0xFE 0xA1-0xFE
      • 2: 0x8E 开头
      • 3: 0x8F 开头

汉字编码

  • 全角与半角:双字节中文的 Legacy Problem
    • 双字节西文字符使排版美观
  • 外码(输入码,输入法编码)
    • 数字编码:区位码
    • 拼音编码:全拼、双拼、自然码
    • 字形编码:五笔、表形码、郑码
  • 字形码
    • 字模点阵码
      • Adobe Type1
      • True Type

GB2312

  • 区位码
    • 94个区,每个区94位,每个区位上有一个字符
      • 94 $\times$ 94二维表:区$\times$位
  • 国标码(交换码)
    • 汉字范围为 (0x21,0x21)-(0x7E,0x7E)
    • 将区码和位码分别加上0x20可得国标码
  • 内码(机内码)
    • 0xA1-0xFE 0xA1-0xFE
    • 国标码中最高位从0变1(加0x80)

GBK

gbk

GB18030

gb18030

通过一张“位置偏移表”记录GB 18030四字节区中连续的几块碎片,以便高效处理转换Unicode

代码页

  • 代码页是字符集的具体实现,可以将其理解为一张“字符-字节”映射表,通过查表实现“字符-字节”的翻译
  • .874 泰文
  • .932 日文 Shift-JIS
  • .936 简体中文 GBK
  • .949 韩文
  • .950 繁体中文 Big5
  • .54936 GB18030

Unicode/UCS

  • 保证了与其他字符集的双向兼容
  • Unicode 平面
    • Plane 0: BMP
      • Private Use Zone: 0xE000-0xF8FF
      • Surrogate Zone: 0xD800-0xDFFF
    • SP
  • BOM(Byte-Order Mark)
    • U+FEFF
      • 字节流开头:标记字节序
      • 中间:零宽度不中断空格(3.2后U+2060)
      • 大端 0xFE 0xFF
      • 小端 0xFF 0xFE

UTF-8 编码

  • 变长编码
    • 除了单字节编码外,由多个单字节码元所组成的多字节编码其首字节以外的后续字节均以10开头
首字节 编码 码点范围 有效位数
0 单字节 0x0000 ~ 0x007F(0 ~ 127) 7
110 双字节 0x0080 ~ 0x07FF(128 ~ 2047) 11
1110 三字节 0x0800 ~ 0xFFFF(2048 ~ 65535) 16
11110 四字节 0x10000 ~ 0x1FFFFF(65536 ~ 2097151) 21

UTF-16 编码

码点范围 表示方法
0x0000 ~ 0xD7FF, 0xE000 ~ 0xFFFF 单码元直接表示
0x10000 ~ 0x1FFFFF(65536 ~ 2097151) 代理对
0xD800 ~ 0xDFFF 代理区,无Unicode对应字符
  • 代理对
    • 码位减去0x100000: 0 ~ 0xFFFFF
    • 前导代理: 高位的10比特的值+0xD800: 0xD800 ~ 0xDBFF
    • 后尾代理: 低位的10比特的值+0xDC00: 0xDC00 ~ 0xDFFF

兼容关系

  • ASCII
    • EASCII
    • ISO/IEC 8859
    • GB13000
    • GB2312
      • GBK
        • GB18030
    • Big5
    • Unicode
      • U+0000-U+00FF 与 Latin1 一致

问题

  • 联通:gbk 错误判断为 Unicode
  • U+FFFD: replacement character used to replace an unknown or unrepresentable character
    • utf-8: 0xEF 0xBF 0xBD
    • gbk: 0xEF 0xBF 锟 0xBD 0xEF 斤 0xBF 0xBD 拷
  • 调试模式下VS会给栈内存加上额外的保护段并且用0xCC填充
    • x86 INT 3
    • gbk: 0xCC 0xCC 烫
  • 堆当中则会用0xCD来填充
    • gbk: 0xCD 0xCD 屯屯屯
    • UTF-16: 韩文 쳌쳌쳌쳌
    • BIG-5: 昍昍昍
    • Shift-JIS: フフフフフフ
  • gbk 0xEFBB 锘

终端

  • iconv -f UTF-8 -t GB2312 -o FILE FILE
    • 不兼容编码间转换不可逆
  • vim
    • 改变文件编码 set fileencoding=utf-8
    • 以某种编码打开 vim file -c “e ++enc=GB2312”
  • enca -L chinese|none FILE
  • man
    • man ascii
    • man 5 utf8
    • man gb2312