メインコンテンツまでスキップ

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-0xDF2バイトシーケンス先頭バイト✅ 有効
0xE0-0xEF3バイトシーケンス先頭バイト✅ 有効
0xF0-0xF44バイトシーケンス先頭バイト✅ 有効
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

関連リンク