N2
NanToo
UTF-8 の誕生 — Rob Pike と Ken Thompson がダイナーのランチョンマットに書いた設計
DDEVELOPER
開発10 分で読める

UTF-8 の誕生 — Rob Pike と Ken Thompson がダイナーのランチョンマットに書いた設計

Web ページの <meta charset="UTF-8"> — 開発者が何気なく書くこの 1 行の背後には、1992 年のある夜の物語があります。Bell Labs の Rob PikeKen Thompson がニュージャージーのダイナーでランチョンマットの裏に描いた符号化方式が、30 年後の今、Web トラフィックの 98% 以上で使われる文字エンコーディングになりました。本記事では Pike 本人の 2003 年のメール、RFC 3629、そして Unicode Consortium の公式資料を一次資料に、UTF-8 がなぜこれほど成功したのかを整理します。

#Unicode#UTF-8#文字コード#Ken Thompson#Rob Pike
AD

前史 — ASCII の 128 文字では足りなかった

1960 年代に制定された ASCII (American Standard Code for Information Interchange) は 7 ビット = 128 文字。英語のアルファベット、数字、基本的な記号を網羅しますが、日本語はもちろん、フランス語のアクセント記号すら表現できません。

1980 年代には各国・各ベンダーが独自の拡張を乱立させました: Shift_JIS (日本)、EUC-KR (韓国)、Big5 (台湾)、ISO 8859 シリーズ (欧州)、Windows-1252 (Microsoft)。同じバイト列が文字コードの解釈次第で全く異なる文字に化ける「文字化け」は日常的な問題でした。

この混沌を解決するため、1980 年代後半に Apple と Xerox のエンジニアが中心となり「世界中のすべての文字に一意の番号 (コードポイント) を割り当てる」構想が始まりました。これが Unicode です。

Unicode の誕生 — 1991 年 1 月 3 日

Unicode Consortium は 1991 年 1 月 3 日にカリフォルニア州で法人として設立されました。同年 10 月に Unicode 1.0 (Volume 1) が出版。当初は 16 ビット固定長 (最大 65,536 文字) で十分と考えられていました。

しかし Unicode はあくまで「コードポイント (文字に割り当てる番号)」の体系であり、バイト列としてどう表現するかは別問題です。16 ビット固定のエンコーディング (後の UTF-16) には致命的な問題がありました:

  • ASCII 非互換: ASCII の 'A' = 0x41 が 0x00 0x41 (2 バイト) になり、既存の C 言語プログラムが動かない (NULL バイトが文字列終端と誤認される)
  • バイト順問題: 0x00 0x41 と 0x41 0x00 のどちらが正しいか (エンディアン) を指定する必要がある
  • ファイルサイズ倍増: 英語テキストのサイズが倍になる

Unix / Plan 9 の世界では、これらの問題は受け入れがたいものでした。

1992 年 9 月 — ダイナーのランチョンマット

Rob Pike の 2003 年 4 月 30 日付メール (UTF-8 の歴史として現在も公開されている) によると、事の発端は X/Open の会議でした。ISO 10646 に対する新しいファイルシステム安全な符号化方式 (FSS-UTF, File System Safe UCS Transformation Format) の提案が議論されていたが、Pike と Thompson はその設計に不満を持っていました。

ある水曜日の夕食時、ニュージャージーのダイナーで Pike が Thompson に不満を伝えると、Thompson はその場でランチョンマットの裏にビットパターンを書き始めました。2 人でバイトの先頭ビットパターンを定め、その夜のうちに Thompson がエンコード/デコードの C コードを実装。Pike は C ライブラリとグラフィクスライブラリを修正しました。

月曜日までに Plan 9 (Bell Labs の次世代 OS) を完全に新しいエンコーディングに移行するという約束を果たし、X/Open の委員会に提案。これが採用され、最終的に UTF-8 として標準化されました。

UTF-8 のビット構造 — なぜこの設計なのか

Thompson が設計した UTF-8 のビットパターンは、RFC 3629 で以下のように定義されています:

コードポイント範囲バイト数ビットパターン用途
U+0000 - U+007F10xxxxxxxASCII (英数字・基本記号)
U+0080 - U+07FF2110xxxxx 10xxxxxxラテン拡張、ギリシャ、キリル等
U+0800 - U+FFFF31110xxxx 10xxxxxx 10xxxxxx日本語、中国語、韓国語、他
U+10000 - U+10FFFF411110xxx 10xxxxxx 10xxxxxx 10xxxxxx絵文字、古代文字、数学記号

この設計には 4 つの重要な性質があります:

  • ASCII 完全互換: U+0000〜U+007F は ASCII と同一のバイト (先頭ビット 0)。既存のテキストファイル、C 言語の文字列処理、grep、sed がそのまま動く
  • 自己同期 (self-synchronizing): 先頭バイトは 011 で始まり、継続バイトは 10 で始まる。ストリームの途中から読み始めても、最大 3 バイト戻るだけで文字境界を特定できる
  • バイト順非依存: 1 バイト単位の処理なので、ビッグエンディアン/リトルエンディアンの問題がない (UTF-16 の BOM 問題を回避)
  • NULL バイトが出現しない: U+0000 以外の文字で 0x00 が現れないため、C 言語の strlen()strcmp() がそのまま使える

日本語と UTF-8 — 3 バイトの代償と引き換えの統一

UTF-8 で日本語 (ひらがな、カタカナ、漢字) は 1 文字 3 バイトです。Shift_JIS や EUC-JP では 2 バイトだったため、テキストサイズが約 1.5 倍に増えます。これは UTF-8 が英語圏に有利なエンコーディングであるという批判の根拠でもあります。

しかし Web の文脈では、HTML タグ、CSS、JavaScript のコードはほぼ ASCII であり、日本語はコンテンツ部分に集中します。全体のファイルサイズでみると増加率はずっと小さく、gzip/Brotli 圧縮を適用すれば差はさらに縮まります。

何より、文字化けが原理的に発生しないという利点は計り知れません。Shift_JIS の「5C 問題」(バックスラッシュ 0x5C が漢字の第 2 バイトと衝突し、パス区切りが壊れる) のような構造的欠陥が UTF-8 には存在しません。

RFC 3629 (2003) — 4 バイト上限の確定

UTF-8 の標準化は 2 段階を経ました:

  • RFC 2279 (1998 年 1 月): François Yergeau 著。最大 6 バイトのシーケンスを許容 (U+7FFFFFFF まで)
  • RFC 3629 (2003 年 11 月): 同じ Yergeau 著。RFC 2279 を廃止し、最大 4 バイト (U+10FFFF まで) に制限

なぜ 4 バイトに制限したのか? Unicode Consortium と ISO 10646 が協議し、コードポイント空間を U+10FFFF (約 111 万文字) に限定することで合意したためです。これにより UTF-16 のサロゲートペア方式と範囲が一致し、UTF-8、UTF-16、UTF-32 の相互変換が無損失で行えるようになりました。

2026 年現在、Unicode 16.0 で定義されている文字数は約 154,998 文字。111 万のスロットの約 14% しか埋まっておらず、今後数千年分の余裕があります。

UTF-8 の勝利 — Web の 98% を制覇するまで

2000 年代初頭、Web で最も使われていたエンコーディングは ASCII と ISO 8859-1 (西欧) でした。UTF-8 のシェアは 2005 年時点でわずか 10% 程度。

転機は以下の連鎖でした:

  • 2003 年: RFC 3629 で UTF-8 が安定。W3C が XHTML で UTF-8 推奨
  • 2007 年: Google が全サービスを UTF-8 に統一
  • 2008 年: HTML5 仕様草案で <meta charset="UTF-8"> が標準化
  • 2010 年: UTF-8 が Web で最も使用されるエンコーディングに (W3Techs 調査)
  • 2024 年: Web の約 98% が UTF-8 (W3Techs)

「すべてのテキストファイルを UTF-8 で保存し、すべてのプロトコルで UTF-8 を使う」というコンセンサスは、30 年前の文字コード戦争に対する最終回答です。

UTF-8 と UTF-16 と UTF-32 — 使い分け

エンコーディング単位ASCII日本語主な用途
UTF-81-4 バイト1 バイト3 バイトWeb、ファイル、API、Linux/macOS
UTF-162 or 4 バイト2 バイト2 バイトWindows API、Java String、JavaScript String
UTF-324 バイト固定4 バイト4 バイト内部処理 (文字単位のランダムアクセスが必要な場合)

Windows が UTF-16 を使い続けているのは、Windows NT (1993) が Unicode 1.0 の 16 ビット固定長時代に設計されたためです。当時は 16 ビットで全文字が収まると想定されていましたが、Unicode 2.0 (1996) で 16 ビットを超える文字 (サロゲートペア) が追加され、UTF-16 も可変長になりました。

JavaScript の String.length が絵文字で「2」を返す問題も、内部が UTF-16 であることに起因します。"😀".length === 2 は UTF-16 のサロゲートペア (2 つの 16 ビット単位) をカウントしているためです。

まとめ

  • ASCII (128 文字) の限界 → 各国独自コードの乱立 → 文字化け地獄
  • Unicode Consortium: 1991 年 1 月 3 日設立、全文字に一意のコードポイントを割り当て
  • UTF-8: 1992 年 9 月、Rob Pike と Ken Thompson がダイナーのランチョンマットに設計
  • Thompson がその夜に C 実装、数日で Plan 9 全体を移行
  • 設計の 4 原則: ASCII 完全互換、自己同期、バイト順非依存、NULL バイト非出現
  • 日本語は 3 バイト/文字 (Shift_JIS 比 1.5 倍) だが、文字化けの根絶と引き換え
  • RFC 2279 (1998) → RFC 3629 (2003) で 4 バイト上限に確定
  • 2024 年時点で Web の 98% が UTF-8 — 文字コード戦争の最終回答

参考文献・ソース

記事作成に関する注記

本記事は AI(大規模言語モデル)を編集補助として活用して作成しています。 公開前に編集者が内容を確認していますが、事実誤認・仕様の解釈ミス・最新情報との齟齬が含まれる可能性があります。 重要な判断を行う際は、本文中の一次ソースや公式ドキュメントを必ずご自身でご確認ください。 誤りにお気づきの場合は、お問い合わせフォームよりご連絡いただけると助かります。

🔧 関連ツール

📚 関連記事

AD