Skip to main content

4. Syntax of UTF-8 Byte Sequences (UTF-8字节序列语法)

为了方便使用ABNF的实现者,这里给出了UTF-8的ABNF语法定义。

UTF-8字符串定义

UTF-8字符串是表示UCS字符序列的八位字节序列。只有当八位字节序列与以下语法匹配时,它才是有效的UTF-8,该语法源自UTF-8编码规则,并以[RFC2234]的ABNF表示。

ABNF语法

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

语法详解

UTF8-1: 单字节序列

%x00-7F
  • 范围: 0x00 到 0x7F (0-127)
  • 编码: 完整的ASCII范围
  • 模式: 0xxxxxxx

UTF8-2: 双字节序列

%xC2-DF UTF8-tail
  • 首字节: 0xC2 到 0xDF (194-223)
  • 尾字节: 0x80 到 0xBF (128-191)
  • 模式: 110xxxxx 10xxxxxx
  • 注意: 首字节不能是0xC0或0xC1(这会产生过长编码)

UTF8-3: 三字节序列

分为四种情况:

情况1: %xE0 %xA0-BF UTF8-tail

  • 首字节: 0xE0
  • 第二字节: 0xA0 到 0xBF
  • 第三字节: 0x80 到 0xBF
  • 编码范围: U+0800 到 U+0FFF

情况2: %xE1-EC 2( UTF8-tail )

  • 首字节: 0xE1 到 0xEC
  • 后续字节: 两个UTF8-tail (0x80-0xBF)
  • 编码范围: U+1000 到 U+CFFF

情况3: %xED %x80-9F UTF8-tail

  • 首字节: 0xED
  • 第二字节: 0x80 到 0x9F
  • 第三字节: 0x80 到 0xBF
  • 编码范围: U+D000 到 U+D7FF
  • 注意: 避免代理对范围 (U+D800-U+DFFF)

情况4: %xEE-EF 2( UTF8-tail )

  • 首字节: 0xEE 到 0xEF
  • 后续字节: 两个UTF8-tail
  • 编码范围: U+E000 到 U+FFFF

UTF8-4: 四字节序列

分为三种情况:

情况1: %xF0 %x90-BF 2( UTF8-tail )

  • 首字节: 0xF0
  • 第二字节: 0x90 到 0xBF
  • 后续字节: 两个UTF8-tail
  • 编码范围: U+10000 到 U+3FFFF

情况2: %xF1-F3 3( UTF8-tail )

  • 首字节: 0xF1 到 0xF3
  • 后续字节: 三个UTF8-tail
  • 编码范围: U+40000 到 U+FFFFF

情况3: %xF4 %x80-8F 2( UTF8-tail )

  • 首字节: 0xF4
  • 第二字节: 0x80 到 0x8F
  • 后续字节: 两个UTF8-tail
  • 编码范围: U+100000 到 U+10FFFF

无效字节值

以下字节值永远不会出现在有效的UTF-8序列中:

禁止的字节值:
- 0xC0, 0xC1 (会产生过长的2字节序列)
- 0xF5 - 0xFF (超出Unicode范围)

完整字节范围总结

字节值范围含义有效性
0x00-0x7F单字节字符 (ASCII)✅ 有效
0x80-0xBF后续字节✅ 仅作为尾字节
0xC0-0xC1禁止❌ 无效
0xC2-0xDF2字节序列首字节✅ 有效
0xE0-0xEF3字节序列首字节✅ 有效
0xF0-0xF44字节序列首字节✅ 有效
0xF5-0xFF禁止❌ 无效

验证示例

有效序列

示例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后跟0x9F在[0x90-0xBF], 后续两个字节在[0x80-0xBF] → UTF8-4 → ✅ 有效
字符: '😀'

无效序列

示例1: 0xC0 0x80
问题: 0xC0被禁止 → ❌ 无效 (过长编码)

示例2: 0xED 0xA0 0x80
问题: 0xED后跟0xA0不在[0x80-0x9F] → ❌ 无效 (代理对范围)

示例3: 0xF5 0x80 0x80 0x80
问题: 0xF5被禁止 → ❌ 无效 (超出Unicode范围)

示例4: 0xE4 0xBD
问题: 3字节序列不完整 → ❌ 无效 (截断)

⚠️ 重要注意事项

注意 -- UTF-8的权威定义在 [UNICODE] 中。此语法被认为描述了与Unicode描述相同的内容,但不声称具有权威性。敦促实现者依赖权威来源,而不是此ABNF。

实现建议

验证算法伪代码

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

相关链接