4. UTF-8 字节序列语法 (Syntax of UTF-8 Byte Sequences)
为方便使用 ABNF 的实现者, 这里给出 UTF-8 的 ABNF 语法定义.
UTF-8 字符串定义 (UTF-8 String Definition)
UTF-8 字符串是一个八位组序列, 表示一个 UCS 字符序列. 一个八位组序列 只有在 匹配以下语法时才是有效 UTF-8. 该语法源自 UTF-8 的编码规则, 并使用 [RFC2234] 的 ABNF 表示.
ABNF 语法 (ABNF Syntax)
UTF8-octets = *( UTF8-char )
UTF8-char = UTF8-1 / UTF8-2 / UTF8-3 / UTF8-4
UTF8-1 = %x00-7F
UTF8-2 = %xC2-DF UTF8-tail
UTF8-3 = %xE0 %xA0-BF UTF8-tail / %xE1-EC 2( UTF8-tail ) /
%xED %x80-9F UTF8-tail / %xEE-EF 2( UTF8-tail )
UTF8-4 = %xF0 %x90-BF 2( UTF8-tail ) / %xF1-F3 3( UTF8-tail ) /
%xF4 %x80-8F 2( UTF8-tail )
UTF8-tail = %x80-BF
语法说明 (Syntax Explanation)
UTF8-1: 单字节序列 (Single-Byte Sequences)
%x00-7F
- 范围 (Range): 0x00 到 0x7F (0-127)
- 编码 (Encoding): 完整 ASCII 范围
- 模式 (Pattern):
0xxxxxxx
UTF8-2: 双字节序列 (Two-Byte Sequences)
%xC2-DF UTF8-tail
- 首字节 (First byte): 0xC2 到 0xDF (194-223)
- 尾字节 (Tail byte): 0x80 到 0xBF (128-191)
- 模式 (Pattern):
110xxxxx 10xxxxxx - 说明 (Note): 首字节不能为 0xC0 或 0xC1 (否则会产生过长编码)
UTF8-3: 三字节序列 (Three-Byte Sequences)
四种情况:
情况 1: %xE0 %xA0-BF UTF8-tail
- 首字节 (First byte): 0xE0
- 第二字节 (Second byte): 0xA0 到 0xBF
- 第三字节 (Third byte): 0x80 到 0xBF
- 编码范围 (Encoding range): U+0800 到 U+0FFF
情况 2: %xE1-EC 2( UTF8-tail )
- 首字节 (First byte): 0xE1 到 0xEC
- 后续字节 (Following bytes): 两个 UTF8-tail (0x80-0xBF)
- 编码范围 (Encoding range): U+1000 到 U+CFFF
情况 3: %xED %x80-9F UTF8-tail
- 首字节 (First byte): 0xED
- 第二字节 (Second byte): 0x80 到 0x9F
- 第三字节 (Third byte): 0x80 到 0xBF
- 编码范围 (Encoding range): U+D000 到 U+D7FF
- 说明 (Note): 避开代理对范围 (U+D800-U+DFFF)
情况 4: %xEE-EF 2( UTF8-tail )
- 首字节 (First byte): 0xEE 到 0xEF
- 后续字节 (Following bytes): 两个 UTF8-tail
- 编码范围 (Encoding range): U+E000 到 U+FFFF
UTF8-4: 四字节序列 (Four-Byte Sequences)
三种情况:
情况 1: %xF0 %x90-BF 2( UTF8-tail )
- 首字节 (First byte): 0xF0
- 第二字节 (Second byte): 0x90 到 0xBF
- 后续字节 (Following bytes): 两个 UTF8-tail
- 编码范围 (Encoding range): U+10000 到 U+3FFFF
情况 2: %xF1-F3 3( UTF8-tail )
- 首字节 (First byte): 0xF1 到 0xF3
- 后续字节 (Following bytes): 三个 UTF8-tail
- 编码范围 (Encoding range): U+40000 到 U+FFFFF
情况 3: %xF4 %x80-8F 2( UTF8-tail )
- 首字节 (First byte): 0xF4
- 第二字节 (Second byte): 0x80 到 0x8F
- 后续字节 (Following bytes): 两个 UTF8-tail
- 编码范围 (Encoding range): U+100000 到 U+10FFFF
无效字节值 (Invalid Byte Values)
以下字节值 永远不会 出现在有效 UTF-8 序列中:
被禁止的字节值:
- 0xC0, 0xC1 (会产生过长的 2 字节序列)
- 0xF5 - 0xFF (超出 Unicode 范围)
完整字节范围汇总 (Complete Byte Range Summary)
| 字节值范围 (Byte Value Range) | 含义 (Meaning) | 有效性 (Validity) |
|---|---|---|
| 0x00-0x7F | 单字节字符 (ASCII) | ✅ 有效 |
| 0x80-0xBF | 续字节 (Continuation byte) | ✅ 仅作为尾部有效 |
| 0xC0-0xC1 | 被禁止 | ❌ 无效 |
| 0xC2-0xDF | 2 字节序列首字节 | ✅ 有效 |
| 0xE0-0xEF | 3 字节序列首字节 | ✅ 有效 |
| 0xF0-0xF4 | 4 字节序列首字节 | ✅ 有效 |
| 0xF5-0xFF | 被禁止 | ❌ 无效 |
验证示例 (Validation Examples)
有效序列 (Valid Sequences)
示例 1: 0x41
检查: 0x41 位于 [0x00-0x7F] → UTF8-1 → ✅ 有效
字符: 'A'
示例 2: 0xC2 0xA9
检查: 0xC2 位于 [0xC2-0xDF], 0xA9 位于 [0x80-0xBF] → UTF8-2 → ✅ 有效
字符: '©'
示例 3: 0xE4 0xBD 0xA0
检查: 0xE4 位于 [0xE1-0xEC], 后续两个字节位于 [0x80-0xBF] → UTF8-3 → ✅ 有效
字符: '你'
示例 4: 0xF0 0x9F 0x98 0x80
检查: 0xF0 后接位于 [0x90-0xBF] 的 0x9F, 后续两个字节位于 [0x80-0xBF] → UTF8-4 → ✅ 有效
字符: '😀'
无效序列 (Invalid Sequences)
示例 1: 0xC0 0x80
问题: 0xC0 被禁止 → ❌ 无效 (过长编码)
示例 2: 0xED 0xA0 0x80
问题: 0xED 后接的 0xA0 不在 [0x80-0x9F] 中 → ❌ 无效 (代理对范围)
示例 3: 0xF5 0x80 0x80 0x80
问题: 0xF5 被禁止 → ❌ 无效 (超出 Unicode 范围)
示例 4: 0xE4 0xBD
问题: 3 字节序列不完整 → ❌ 无效 (被截断)
⚠️ 重要说明 (Important Note)
NOTE -- UTF-8 的权威定义位于 [UNICODE]. 本语法被认为描述了与 Unicode 所描述内容相同的事物, 但并不声称具有权威性. 建议实现者依赖权威来源, 而不是依赖此 ABNF.
实现建议 (Implementation Suggestion)
验证算法伪代码 (Validation Algorithm Pseudocode)
def is_valid_utf8(bytes):
i = 0
while i < len(bytes):
b = bytes[i]
if b <= 0x7F: # UTF8-1
i += 1
elif 0xC2 <= b <= 0xDF: # UTF8-2
if i + 1 >= len(bytes) or not (0x80 <= bytes[i+1] <= 0xBF):
return False
i += 2
elif b == 0xE0: # UTF8-3 case 1
if i + 2 >= len(bytes):
return False
if not (0xA0 <= bytes[i+1] <= 0xBF and 0x80 <= bytes[i+2] <= 0xBF):
return False
i += 3
elif 0xE1 <= b <= 0xEC: # UTF8-3 case 2
if i + 2 >= len(bytes):
return False
if not (0x80 <= bytes[i+1] <= 0xBF and 0x80 <= bytes[i+2] <= 0xBF):
return False
i += 3
elif b == 0xED: # UTF8-3 case 3
if i + 2 >= len(bytes):
return False
if not (0x80 <= bytes[i+1] <= 0x9F and 0x80 <= bytes[i+2] <= 0xBF):
return False
i += 3
elif 0xEE <= b <= 0xEF: # UTF8-3 case 4
if i + 2 >= len(bytes):
return False
if not (0x80 <= bytes[i+1] <= 0xBF and 0x80 <= bytes[i+2] <= 0xBF):
return False
i += 3
elif b == 0xF0: # UTF8-4 case 1
if i + 3 >= len(bytes):
return False
if not (0x90 <= bytes[i+1] <= 0xBF and
0x80 <= bytes[i+2] <= 0xBF and
0x80 <= bytes[i+3] <= 0xBF):
return False
i += 4
elif 0xF1 <= b <= 0xF3: # UTF8-4 case 2
if i + 3 >= len(bytes):
return False
if not (0x80 <= bytes[i+1] <= 0xBF and
0x80 <= bytes[i+2] <= 0xBF and
0x80 <= bytes[i+3] <= 0xBF):
return False
i += 4
elif b == 0xF4: # UTF8-4 case 3
if i + 3 >= len(bytes):
return False
if not (0x80 <= bytes[i+1] <= 0x8F and
0x80 <= bytes[i+2] <= 0xBF and
0x80 <= bytes[i+3] <= 0xBF):
return False
i += 4
else:
return False # Invalid byte
return True