コードポイントとは — Unicode・UTF-8・\uXXXXの関係

コードポイントは、Unicodeがそれぞれの文字に割り当てた一意の番号です。 なら U+3042。この番号を実際のバイト列に変換する規則が UTF-8UTF-16 で、両者は別の概念です。本記事ではコードポイントの意味、UTF-8で1〜4バイトになる仕組み、絵文字がサロゲートペアになる理由を、実際に確かめる方法つきで整理します。

3つを分けて考える:コードポイント(U+○○○○という番号)/UTF-8(そのバイト列)/UTF-16(\uXXXXという16ビット単位)は、それぞれ別の層です。混同すると「1文字なのに長さが2」といった現象が理解できなくなります。

1. コードポイントとは

Unicodeは世界中の文字に通し番号を振った巨大な文字集合です。この各文字に対応する番号がコードポイントで、慣習として U+ のあとに16進数で書きます。

ここまでは「番号を決めた」だけで、コンピュータに保存する形(バイト)はまだ決まっていません。それを担うのが符号化方式です。

2. UTF-8 — 1〜4バイトへの符号化

UTF-8は、コードポイントの大きさに応じて1〜4バイトで表す方式です。ASCIIと互換で、Webでもっとも広く使われています。

範囲UTF-8のバイト数
U+0000〜U+007F1バイトA → 41
U+0080〜U+07FF2バイトé → C3 A9
U+0800〜U+FFFF3バイトあ → E3 81 82
U+10000〜U+10FFFF4バイト😀 → F0 9F 98 80

つまり「日本語1文字は3バイト」というのは、多くの文字がこの3バイト範囲に入るためです。文字数とバイト数が一致しないのはこのためで、データベースの桁数設計などで意識する必要があります。

3. UTF-16 と \uXXXX

UTF-16は16ビット(2バイト)単位で表す方式で、JavaScriptの文字列が内部で採用しています。U+FFFF以下は1単位、それを超える文字はサロゲートペアという2単位で表します。ソースコードやJSON文字列でよく見る \uXXXX は、このUTF-16の1単位を16進で書いたものです。

4. 絵文字がサロゲートペアになる理由

UTF-16は元々16ビットで表せる範囲(U+FFFFまで)しか想定していませんでした。それを超える文字を表すため、予約された範囲(D800〜DFFF)の2単位を組み合わせて1つのコードポイントを表す仕組みがサロゲートペアです。😀 は上位 D83D・下位 DE00 のペアで表されます。

この結果、JavaScriptの "😀".length2 になります。コードポイントは1つでも、UTF-16単位では2つだからです。

5. 実際に試せる方法(JavaScript)

コンソールやNode.jsで、コードポイント・UTF-8バイト・UTF-16単位をそれぞれ確認できます。

const ch = "😀";

// コードポイント(U+)
console.log(ch.codePointAt(0).toString(16).toUpperCase()); // 1F600

// UTF-8 バイト列
console.log([...new TextEncoder().encode(ch)]
  .map(b => b.toString(16).toUpperCase())); // ["F0","9F","98","80"]

// UTF-16 単位(\uXXXX)
console.log(ch.length);        // 2(サロゲートペア)
console.log([...ch].length);   // 1(コードポイント単位で数える)

複数の文字をまとめて表で確認したいときは、下記のコードポイント確認ツールに文字を貼り付けてください。1文字ごとに U+・10進・UTF-8・UTF-16 を一覧表示します。

Free Tool コードポイント確認ツールで調べる 文字を入力すると、各文字の U+ コードポイント・10進・UTF-8バイト・UTF-16(\uXXXX)を一覧表示します。すべてブラウザ内で完結します。

よくある質問(FAQ)

コードポイントと文字コードは同じ意味ですか?

厳密には違います。コードポイントはUnicodeが各文字に割り当てた抽象的な番号(例:あ は U+3042)で、それを実際のバイト列に変換する規則がUTF-8やUTF-16といった符号化方式です。日常会話ではまとめて文字コードと呼ぶことも多いですが、番号そのものと、バイトへの符号化方式は分けて考えると理解しやすくなります。

1文字が何バイトになるかはどう決まりますか?

符号化方式とコードポイントの大きさで決まります。UTF-8ではU+0000〜U+007F(ASCII)が1バイト、日本語の多くが3バイト、絵文字などが4バイトです。UTF-16ではU+FFFF以下が2バイト、それを超える文字は4バイト(サロゲートペア)になります。同じ文字でも方式が違えばバイト数は変わります。

JavaScriptのlengthで絵文字が2と数えられるのはなぜですか?

JavaScriptの文字列はUTF-16で管理され、lengthは16ビット単位の個数を返すためです。U+FFFFを超える絵文字はサロゲートペアで2単位になるので、length は2になります。コードポイント単位で数えたいときは、for...of や Array.from、[...str] を使うと1文字として扱えます。

← 技術ブログ一覧へ戻る