BMP (基本多言語面)
Unicode の最初の 65,536 個のコードポイント (U+0000〜U+FFFF) を含む領域。日常的に使われるほとんどの文字がここに収録されており、この範囲外の文字は UTF-16 ではサロゲートペアで表現される。
BMP (Basic Multilingual Plane、基本多言語面) は、Unicode の 17 個の「面」(plane) のうち最初の面 (Plane 0) です。U+0000 から U+FFFF までの 65,536 個のコードポイントを含み、ASCII、ラテン文字、ギリシャ文字、キリル文字、アラビア文字、ひらがな、カタカナ、CJK 統合漢字の基本セット (約 20,000 字) など、世界の主要な文字体系のほとんどがここに収録されています。
BMP の外側には補助面 (Supplementary Planes) が 16 面あります。Plane 1 (SMP、補助多言語面) には絵文字、古代文字、音楽記号などが含まれます。Plane 2 (SIP、補助表意文字面) には、以前の文字コード規格に含まれていなかった漢字が収録されています。2026 年時点では CJK 統合漢字拡張 B・C・D・E・F・I がこの面にあり、拡張 G・H・J は Plane 3 (TIP、第三次表意文字面) に置かれています。拡張の記号順と面の番号は一致しないため、「拡張 B 以降はすべて Plane 2」と考えると外れます。これらの補助面の文字は U+10000 以上のコードポイントを持ちます。
BMP と補助面の区別が文字数カウントに影響するのは、UTF-16 エンコーディングを使用する環境です。UTF-16 では BMP の文字は 2 バイト (1 コードユニット) で表現できますが、補助面の文字は 4 バイト (2 コードユニット = サロゲートペア) が必要です。JavaScript の String.length はコードユニット数を返すため、絵文字 (補助面) を含む文字列では見た目の文字数より大きな値が返ります。
具体例を見てみましょう。「A」(U+0041、BMP) は length が 1 です。「𠮷」(U+20BB7、CJK 統合漢字拡張 B) は BMP 外の文字で、length が 2 になります。「😀」(U+1F600、絵文字) も BMP 外で length は 2 です。さらに「👨👩👧👦」(家族の絵文字) は 7 つのコードポイント (うち 4 つが BMP 外) で構成され、length は 11 になります。BMP 外の 4 文字が 2 コードユニットずつ、間の ZWJ が 3 つで 1 コードユニットずつという内訳です。
実務で BMP の境界が問題になる典型は、保存先が BMP 内の文字しか扱えない場合です。MySQL の utf8mb3 (かつての utf8) は 1 文字あたり最大 3 バイトで BMP の文字だけを保存できる文字セットで、絵文字や拡張漢字を入れるとエラーになるか文字が失われます。絵文字を含むテキストを保存するなら utf8mb4 を選ぶ必要があります。文字数の上限を UTF-16 コードユニット数で決めているフォームでも同じ境界が顔を出し、絵文字 1 つで 2 文字分を消費します。ある文字が BMP 外かどうかは codePointAt(0) > 0xFFFF で判定できます。
正確な文字数カウントには、BMP 内外を区別しない方法が必要です。JavaScript では Array.from(str).length や [...str].length でコードポイント単位の文字数を取得できます。さらに正確を期すなら、Intl.Segmenter を使って書記素クラスタ単位でカウントすれば、結合文字や絵文字シーケンスも 1 文字として正しく数えられます。
BMP の中にも特殊な領域があります。U+D800〜U+DFFF はサロゲート用に予約されており、単独では有効な文字を表しません。U+E000〜U+F8FF は私用領域 (Private Use Area) で、フォントメーカーや企業が独自の文字を割り当てるために使います。U+FDD0〜U+FDEF と各面の末尾 2 コードポイントは「非文字」(noncharacter) として永久に文字に割り当てられません。