Skip to content

Unicode编码UTF-8、UTF-16、UTF-32的区别

Unicode 基本概念

Unicode 是一个国际标准,为世界上几乎所有的文字系统中的每个字符分配了唯一的数字标识(码点)。Unicode 编码空间从 U+0000U+10FFFF,共有 1,114,112 个码点,分为17个平面:

  • 基本多语言平面(BMP):U+0000 - U+FFFF
  • 16个辅助平面:U+10000 - U+10FFFF

主要 Unicode 编码方式

1. UTF-8

变长编码,使用1-4个字节。

  • 特点

    • 兼容 ASCII
    • 节省空间
    • 自同步能力强
    • 没有字节序问题
  • 编码规则

    • 1字节:0xxxxxxx(ASCII 字符)
    • 2字节:110xxxxx 10xxxxxx(拉丁文扩展、希腊文等)
    • 3字节:1110xxxx 10xxxxxx 10xxxxxx(中日韩文字等)
    • 4字节:11110xxx 10xxxxxx 10xxxxxx 10xxxxxx(表情符号、古文字等)
  • 使用场景

    • Web 页面(HTML5 默认编码)
    • 文件存储
    • 网络传输
    • Linux/Unix 系统
    • 跨平台应用

2. UTF-16

变长编码,使用2或4个字节。

  • 特点

    • 基本平面字符使用2字节
    • 辅助平面字符使用4字节(代理对)
    • 有字节序问题(需要 BOM 标记)
  • 编码规则

    • 基本平面:直接使用码点值
    • 辅助平面:使用代理对
      • 高代理:(码点 - 0x10000) / 0x400 + 0xD800
      • 低代理:(码点 - 0x10000) % 0x400 + 0xDC00
  • 使用场景

    • Windows 操作系统内部
    • JavaScript 内部字符串表示
    • Java 字符串
    • .NET 框架
    • 许多编程语言的内部表示

3. UTF-32

固定长度编码,使用4个字节。

  • 特点

    • 最简单的编码方式
    • 直接使用码点值
    • 有字节序问题
    • 空间效率低
  • 编码规则

    • 直接使用码点值,不足补0
  • 使用场景

    • 需要随机访问字符的场景
    • 某些 Unix 系统
    • 某些编程语言的内部处理
    • 字符处理算法

4. GB18030

中国国家标准,兼容 GB2312 和 GBK。

  • 特点

    • 兼容 ASCII
    • 可表示所有 Unicode 字符
    • 变长编码(1、2或4字节)
  • 使用场景

    • 中国政府系统
    • 某些需要符合中国标准的软件

5. Shift-JIS

日本编码标准。

  • 特点

    • 变长编码(1或2字节)
    • 兼容 ASCII
  • 使用场景

    • 日本本地软件
    • 日语网站

6. ISO-8859 系列

欧洲语言的8位编码标准。

  • 特点

    • 单字节编码
    • 兼容 ASCII
    • 不同语言有不同变种(如ISO-8859-1、ISO-8859-2等)
  • 使用场景

    • 欧洲语言文档
    • 老旧系统

编码示例对比

基本平面字符示例

以汉字"马"为例(位于基本平面):

Unicode 码点:U+9A6C (十进制:39532)

UTF-32BE: 00 00 9A 6C     (4字节)
UTF-32LE: 6C 9A 00 00     (4字节)
UTF-16BE: 9A 6C           (2字节)
UTF-16LE: 6C 9A           (2字节)
UTF-8:    E9 A9 AC        (3字节)
GB18030:  C2 ED           (2字节)

辅助平面字符示例

以汉字"𡠀"为例(位于辅助平面):

Unicode 码点:U+21800 (十进制:137216)

UTF-32BE: 00 02 18 00     (4字节)
UTF-32LE: 00 18 02 00     (4字节)
UTF-16BE: D8 46 DC 00     (4字节,代理对)
UTF-16LE: 46 D8 00 DC     (4字节,代理对)
UTF-8:    F0 A1 A0 80     (4字节)
GB18030:  95 32 82 36     (4字节)

ASCII 字符示例

以字母"A"为例:

Unicode 码点:U+0041 (十进制:65)

UTF-32BE: 00 00 00 41     (4字节)
UTF-32LE: 41 00 00 00     (4字节)
UTF-16BE: 00 41           (2字节)
UTF-16LE: 41 00           (2字节)
UTF-8:    41              (1字节)
GB18030:  41              (1字节)
ISO-8859: 41              (1字节)

字节序(Byte Order)

对于多字节编码(如UTF-16和UTF-32),存在字节序问题:

  • 大端序(Big Endian, BE):高位字节在前
  • 小端序(Little Endian, LE):低位字节在前

为了标识字节序,常在文件开头添加字节序标记(BOM):

  • UTF-8 BOM:EF BB BF(不必要但有时使用)
  • UTF-16BE BOM:FE FF
  • UTF-16LE BOM:FF FE
  • UTF-32BE BOM:00 00 FE FF
  • UTF-32LE BOM:FF FE 00 00

编程语言中的 Unicode 处理

JavaScript

demo.js
javascript
// 字符串内部使用UTF-16
const char = "𡠀";
console.log(char.length);           // 2(代理对占用两个代码单元)
console.log(char.codePointAt(0));   // 137216
console.log("\u{21800}");           // 𡠀(ES6支持)

// 正确处理字符
console.log([...char].length);      // 1

Python

demo.py
python
# Python 3 字符串内部使用 Unicode
char = "𡠀"
print(len(char))                    # 1(Python正确处理码点)
print(ord(char))                    # 137216
print("\U00021800")                 # 𡠀

# 编码转换
utf8_bytes = char.encode('utf-8')   # b'\xf0\xa1\xa0\x80'
utf16_bytes = char.encode('utf-16') # b'\xff\xfeF\xd8\x00\xdc'(带BOM)

Java

demo.java
java
String char = "𡠀";
System.out.println(char.length());           // 2(Java使用UTF-16)
System.out.println(char.codePointCount(0, char.length())); // 1
System.out.println(Character.toCodePoint(
    char.charAt(0), char.charAt(1)));        // 137216

编码选择建议

  1. Web开发

    • 使用 UTF-8,这是HTML5的默认编码
    • 明确在HTML中声明:<meta charset="UTF-8">
  2. 数据库

    • 推荐使用 UTF-8 或 UTF-8mb4(MySQL中支持表情符号)
    • 注意字段长度设计
  3. API和数据交换

    • 使用 UTF-8,这是JSON的标准编码
  4. 文件存储

    • 跨平台:UTF-8
    • Windows专用:可考虑 UTF-16
    • 谨慎使用BOM
  5. 内存处理

    • 随机访问需求高:考虑 UTF-32
    • 内存受限:考虑 UTF-8

Released under the MIT License.