Skip to main content

RFC 3629 - UTF-8, a transformation format of ISO 10646

UTF-8, ISO 10646的转换格式

发布日期: 2003年11月
状态: 互联网标准 (STD 63)
作者: F. Yergeau (Alis Technologies)
废止: RFC 2279
类别: Standards Track


摘要 (Abstract)

ISO/IEC 10646-1定义了一个称为通用字符集 (Universal Character Set, UCS) 的大型字符集,涵盖了世界上大多数书写系统。然而,最初提出的UCS编码与许多当前应用程序和协议不兼容,这导致了UTF-8的开发,即本备忘录的主题。UTF-8的特点是保留完整的US-ASCII范围,提供与依赖US-ASCII值但对其他值透明的文件系统、解析器和其他软件的兼容性。本备忘录废止并替代RFC 2279。


本备忘录的状态 (Status of this Memo)

本文档为互联网社区规定了一个互联网标准跟踪协议,并请求讨论和改进建议。有关本协议的标准化状态和地位,请参阅当前版本的"互联网官方协议标准" (STD 1)。本备忘录的分发不受限制。


Copyright (C) The Internet Society (2003). All Rights Reserved.


目录 (Table of Contents)

主要章节


为什么UTF-8很重要?

UTF-8是现代互联网的标准字符编码,几乎所有现代Web应用、API和数据格式都使用UTF-8。

核心优势

特性说明重要性
ASCII兼容ASCII字符编码完全相同⭐⭐⭐⭐⭐
无字节序问题没有大小端问题⭐⭐⭐⭐⭐
自同步可从任意位置开始解码⭐⭐⭐⭐
空间效率英文1字节,中文3字节⭐⭐⭐⭐
全球支持支持所有Unicode字符⭐⭐⭐⭐⭐

UTF-8编码规则快速参考

编码表

Unicode范围          字节数  UTF-8字节模式
─────────────────────────────────────────────
U+0000 - U+007F 1 0xxxxxxx
U+0080 - U+07FF 2 110xxxxx 10xxxxxx
U+0800 - U+FFFF 3 1110xxxx 10xxxxxx 10xxxxxx
U+10000 - U+10FFFF 4 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

字符范围覆盖

1字节 (ASCII):
- 拉丁字母、数字、基本标点
- 控制字符
- 范围: U+0000 - U+007F

2字节:
- 拉丁扩展
- 希腊文、西里尔文、阿拉伯文、希伯来文
- 范围: U+0080 - U+07FF

3字节:
- 中日韩文字(CJK)
- 大部分其他语言文字
- 范围: U+0800 - U+FFFF

4字节:
- Emoji表情符号
- 历史文字、罕用汉字
- 范围: U+10000 - U+10FFFF

编码示例

ASCII字符

字符: 'A'
Unicode: U+0041
二进制: 0100 0001
UTF-8: 0x41
字节数: 1

编码过程:
U+0041 < U+007F → 使用1字节模板
0xxxxxxx → 01000001 → 0x41

中文字符

字符: '你'
Unicode: U+4F60
二进制: 0100 1111 0110 0000
UTF-8: 0xE4 0xBD 0xA0
字节数: 3

编码过程:
U+4F60在U+0800-U+FFFF范围 → 使用3字节模板
1110xxxx 10xxxxxx 10xxxxxx
↓ ↓ ↓
0100 111101 100000
↓ ↓ ↓
11100100 10111101 10100000
0xE4 0xBD 0xA0

Emoji表情

字符: '😀'
Unicode: U+1F600
二进制: 0001 1111 0110 0000 0000 0000
UTF-8: 0xF0 0x9F 0x98 0x80
字节数: 4

编码过程:
U+1F600在U+10000-U+10FFFF范围 → 使用4字节模板
11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
↓ ↓ ↓ ↓
000011 111101 100000 000000
↓ ↓ ↓ ↓
11110000 10011111 10011000 10000000
0xF0 0x9F 0x98 0x80

UTF-8的独特特性

1. ASCII兼容性

ASCII文件 = 有效的UTF-8文件

示例:
Hello World (ASCII)
同时也是有效的UTF-8

原因:
ASCII使用7位 (0xxxxxxx)
UTF-8的1字节形式就是ASCII

2. 自同步 (Self-Synchronizing)

UTF-8字节流:
... E4 BD A0 E5 A5 BD ...
你 好

从任意位置开始:
- 首字节 (1110xxxx 或 110xxxxx 或 11110xxx) 标识字符开始
- 后续字节 (10xxxxxx) 绝不会被误认为首字节

示例:
E4 BD A0 E5 A5 BD
↑ ↑
从这里开始可以识别出这是后续字节
从这里开始可以识别出新字符

3. 无字节序问题

UTF-16需要BOM:
FE FF ... (Big Endian)
FF FE ... (Little Endian)

UTF-8不需要:
字节顺序固定,从高到低
无需BOM指示字节序

常见应用

Web开发

<!-- HTML文件 -->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>UTF-8示例</title>
</head>
<body>
<p>你好,世界! Hello, World! 😀</p>
</body>
</html>

HTTP协议

HTTP/1.1 200 OK
Content-Type: text/html; charset=UTF-8
Content-Length: 1234

<!DOCTYPE html>...

JSON数据

{
"name": "张三",
"message": "Hello 世界",
"emoji": "😀"
}

数据库

CREATE DATABASE mydb CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

安全考虑要点

⚠️ 非最短形式攻击

禁止使用过长编码:

正确: 'A' → 0x41 (1字节)
错误: 'A' → 0xC0 0x81 (2字节,过长)
'A' → 0xE0 0x80 0x81 (3字节,过长)

危险:
过长编码可能绕过安全检查
例如: 路径遍历 "../" 的过长编码

⚠️ 无效序列

必须拒绝:
- 孤立的后续字节 (10xxxxxx)
- 超出Unicode范围 (>U+10FFFF)
- UTF-16代理对 (U+D800-U+DFFF)
- 截断的多字节序列

编程语言支持

Python

# 编码
s = "你好世界"
b = s.encode('utf-8') # bytes对象

# 解码
s = b.decode('utf-8') # str对象

# 文件操作
with open('file.txt', 'r', encoding='utf-8') as f:
content = f.read()

JavaScript

// 编码
const str = "你好世界";
const encoder = new TextEncoder();
const bytes = encoder.encode(str); // Uint8Array

// 解码
const decoder = new TextDecoder('utf-8');
const text = decoder.decode(bytes); // string

Java

// 编码
String str = "你好世界";
byte[] bytes = str.getBytes(StandardCharsets.UTF_8);

// 解码
String decoded = new String(bytes, StandardCharsets.UTF_8);

// 文件操作
Files.readString(path, StandardCharsets.UTF_8);

Go

// Go的string原生就是UTF-8
s := "你好世界"

// 转换为字节切片
b := []byte(s)

// 从字节切片转换
s = string(b)

性能特性

空间效率对比

文本类型UTF-8UTF-16UTF-32
英文1字节2字节4字节
中文3字节2字节4字节
Emoji4字节4字节4字节
英文为主的文本: UTF-8最优
中日韩为主的文本: UTF-16略优
混合文本: UTF-8通常最优


快速诊断工具

识别UTF-8编码

def is_utf8(data):
"""检测数据是否为有效UTF-8"""
try:
data.decode('utf-8')
return True
except UnicodeDecodeError:
return False

修复编码问题

# 常见问题: 双重编码
# 原始: "你好"
# 错误显示: "ä½ å¥½"

# 修复方法:
text = "ä½ å¥½"
fixed = text.encode('latin1').decode('utf-8')
# 结果: "你好"

重要提示: UTF-8是现代互联网的默认标准。始终使用UTF-8编码,避免使用遗留编码如GBK、ISO-8859-1、Windows-1252等。所有新项目都应该使用UTF-8作为唯一的字符编码。