4. Syntax of UTF-8 Byte Sequences (UTF-8バイトシーケンスの構文)
ABNFを使用する実装者の便宜のため、ここではUTF-8のABNF構文による定義を示します。
UTF-8文字列の定義 (UTF-8 String Definition)
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
構文の説明 (Syntax Explanation)
UTF8-1: 単一バイトシーケンス
%x00-7F
- 範囲: 0x00から0x7F(0-127)
- エンコーディング: 完全なASCII範囲
- パターン:
0xxxxxxx
UTF8-2: 2バイトシーケンス
%xC2-DF UTF8-tail
- 先頭バイト: 0xC2から0xDF(194-223)
- 後続バイト: 0x80から0xBF(128-191)
- パターン:
110xxxxx 10xxxxxx - 注意: 先頭バイトは0xC0または0xC1にはできません(過長エンコーディングを生成します)
UTF8-3: 3バイトシーケンス
4つのケース:
ケース1: %xE0 %xA0-BF UTF8-tail
- 先頭バイト: 0xE0
- 2番目のバイト: 0xA0から0xBF
- 3番目のバイト: 0x80から0xBF
- エンコーディング範囲: U+0800からU+0FFF
ケース2: %xE1-EC 2( UTF8-tail )
- 先頭バイト: 0xE1から0xEC
- 後続バイト: 2つのUTF8-tail(0x80-0xBF)
- エンコーディング範囲: U+1000からU+CFFF
ケース3: %xED %x80-9F UTF8-tail
- 先頭バイト: 0xED
- 2番目のバイト: 0x80から0x9F
- 3番目のバイト: 0x80から0xBF
- エンコーディング範囲: U+D000からU+D7FF
- 注意: サロゲートペア範囲(U+D800-U+DFFF)を回避
ケース4: %xEE-EF 2( UTF8-tail )
- 先頭バイト: 0xEEから0xEF
- 後続バイト: 2つのUTF8-tail
- エンコーディング範囲: U+E000からU+FFFF
UTF8-4: 4バイトシーケンス
3つのケース:
ケース1: %xF0 %x90-BF 2( UTF8-tail )
- 先頭バイト: 0xF0
- 2番目のバイト: 0x90から0xBF
- 後続バイト: 2つのUTF8-tail
- エンコーディング範囲: U+10000からU+3FFFF
ケース2: %xF1-F3 3( UTF8-tail )
- 先頭バイト: 0xF1から0xF3
- 後続バイト: 3つのUTF8-tail
- エンコーディング範囲: U+40000からU+FFFFF
ケース3: %xF4 %x80-8F 2( UTF8-tail )
- 先頭バイト: 0xF4
- 2番目のバイト: 0x80から0x8F
- 後続バイト: 2つのUTF8-tail
- エンコーディング範囲: U+100000からU+10FFFF
無効なバイト値 (Invalid Byte Values)
以下のバイト値は、有効なUTF-8シーケンスには決して現れません:
禁止されるバイト値:
- 0xC0, 0xC1 (過長な2バイトシーケンスを生成します)
- 0xF5 - 0xFF (Unicode範囲を超えます)
完全なバイト範囲の要約 (Complete Byte Range Summary)
| バイト値範囲 | 意味 | 有効性 |
|---|---|---|
| 0x00-0x7F | 単一バイト文字(ASCII) | ✅ 有効 |
| 0x80-0xBF | 後続バイト | ✅ 後続バイトとしてのみ有効 |
| 0xC0-0xC1 | 禁止 | ❌ 無効 |
| 0xC2-0xDF | 2バイトシーケンス先頭バイト | ✅ 有効 |
| 0xE0-0xEF | 3バイトシーケンス先頭バイト | ✅ 有効 |
| 0xF0-0xF4 | 4バイトシーケンス先頭バイト | ✅ 有効 |
| 0xF5-0xFF | 禁止 | ❌ 無効 |
検証例 (Validation Examples)
有効なシーケンス
例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]内、次の2バイトは[0x80-0xBF]内 → UTF8-3 → ✅ 有効
文字: '你'
例4: 0xF0 0x9F 0x98 0x80
確認: 0xF0の後に0x9Fは[0x90-0xBF]内、次の2バイトは[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ではなく、権威ある情報源に依拠することが推奨されます。
実装の提案 (Implementation Suggestion)
検証アルゴリズムの擬似コード
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 ケース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 ケース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 ケース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 ケース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 ケース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 ケース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 ケース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 # 無効なバイト
return True