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

RFC 3629 - 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)

本文書は、インターネットコミュニティに対するインターネット標準トラックプロトコルを規定し、改善のための議論と提案を求めるものです。本プロトコルの標準化状態および地位については、「Internet Official Protocol Standards」(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バイト:
- 絵文字
- 歴史的文字、稀な漢字
- 範囲: U+10000 - U+10FFFF

エンコーディングの例

ASCII文字

文字: 'A'
Unicode: U+0041
2進数: 0100 0001
UTF-8: 0x41
バイト数: 1

エンコーディングプロセス:
U+0041 < U+007F → 1バイトテンプレートを使用
0xxxxxxx → 01000001 → 0x41

中国語文字

文字: '你'
Unicode: U+4F60
2進数: 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

絵文字

文字: '😀'
Unicode: U+1F600
2進数: 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の文字列はネイティブでUTF-8
s := "你好世界"

// バイトスライスに変換
b := []byte(s)

// バイトスライスから変換
s = string(b)

パフォーマンス特性

空間効率の比較

テキストタイプUTF-8UTF-16UTF-32
英語1バイト2バイト4バイト
中国語3バイト2バイト4バイト
絵文字4バイト4バイト4バイト
英語中心のテキスト: UTF-8が最適
CJK中心のテキスト: 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を唯一の文字エンコーディングとして使用すべきです。