Unicodeコードポイント、UTF-8、UTF-16とは? 文字コードの仕組みを解説

普通の文字1つから絵文字まで、入力するすべての文字はUnicodeの「コードポイント」に対応づけられています。それがどのように実際のバイト列として保存されるのかを見ていきます。

コードポイントとは文字に割り当てられた番号

Unicodeはすべての文字にU+から始まる16進数の一意な番号(コードポイント)を割り当てています。たとえば「A」はU+0041、にっこり笑う絵文字はU+1F600です。コードポイントは文字を概念として識別するもので、バイトとして保存する方法とは別の話です。

UTF-8は1文字あたり1〜4バイトの可変長

UTF-8は可変長のエンコード方式で、基本的な半角英数字は1バイトで済みますが、アクセント付き文字や日本語などのCJK文字、絵文字はそれ以外の範囲にあり2〜4バイトを使います。そのため文字列のバイト数が見た目の文字数より多くなるのはよくあることです。

UTF-16は通常2バイトだが、時に4バイト必要になる

UTF-16は多くの一般的な文字を2バイト単位1つで表しますが、基本多言語面の外にある文字(絵文字の大部分を含む)は「サロゲートペア」と呼ばれる2バイト単位2つの組み合わせが必要です。コードが「1単位=1文字」と誤って仮定していると、バグの原因になりやすい部分です。

HTMLの数値文字参照はコードポイントを直接使う

😀や😀のようなHTMLの数値文字参照は、コードポイントを10進数または16進数の番号として表現したものです。直接入力や表示ができない文字をHTMLエンティティとして書く際は、まずそのコードポイントを調べることが出発点になります。

関連する文字は「ブロック」としてまとめられている

Unicodeは「基本ラテン文字」「CJK統合漢字」「絵文字」のような名前のブロックにコードポイントを整理し、関連する文字を連続した範囲にまとめています。見慣れないコードポイントがおおよそどんな種類の文字かを判断する手がかりになります。

同じ文字集合に複数のエンコード方式が存在する理由

UTF-8、UTF-16、UTF-32はいずれも同じUnicodeコードポイントを表現しますが、保存効率と処理のしやすさのトレードオフが異なります。UTF-8は英語主体のテキストでコンパクトでありウェブの主流ですが、UTF-16はWindowsやJavaなど古くからのプラットフォームAPIに組み込まれているため、どちらも一方に置き換わることなく広く使われ続けています。

1つの絵文字が複数のコードポイントでできている理由

特定の肌の色の親指を立てた絵文字や家族の絵文字のような多くの現代的な絵文字は、実際には複数のコードポイントをゼロ幅接合子という特殊な文字でつないだ組み合わせで、対応するソフトウェア上では1つの絵文字として表示されます。見た目は似ていても内部のコードポイント列の長さが異なる絵文字がある理由はここにあります。

よくある質問

文字列の文字数とバイト数が一致しないのはなぜですか?

UTF-8のようなエンコードは文字ごとに使うバイト数が異なるためです。半角英数字だけの文字列は文字数とバイト数が一致しますが、アクセント付き文字や日本語、絵文字が加わると、見た目の文字数以上にバイト数が増えていきます。

サロゲートペアとは何のことですか?

UTF-16が通常の2バイト単位に収まらない文字を表現するための仕組みで、2つの特殊な2バイト単位を組み合わせて1つの文字として扱います。ソフトウェアがそれぞれを誤って別々の文字として扱うと、絵文字や珍しい文字が途中で分断され、表示が壊れることがあります。