Unicode

世界中の文字を統一的に表現するための文字コード規格

テキスト処理Web

Unicode とは

Unicode は、世界中の文字 (ラテン文字、漢字、アラビア文字、絵文字など) に一意のコードポイント (U+0041 = 'A') を割り当てる文字コード規格である。Unicode Consortium が管理し、15 万以上の文字を収録している。

エンコーディング

Unicode はコードポイントの割り当てであり、実際のバイト列への変換はエンコーディングが行う。

エンコーディング バイト数 特徴 用途
UTF-8 1〜4 バイト (可変長) ASCII 互換、Web の標準 HTML, JSON, ファイル
UTF-16 2 or 4 バイト JavaScript の内部表現 JavaScript, Java, Windows
UTF-32 4 バイト (固定長) 処理が単純だがメモリ消費大 内部処理

Web では UTF-8 が事実上の標準だ。HTML の <meta charset="UTF-8"> で指定する。

JavaScript での Unicode

JavaScript の文字列は内部的に UTF-16 で表現される。これが絵文字やサロゲートペアで問題を起こす。

// 基本多言語面 (BMP) の文字: 1 つの UTF-16 コードユニット
'A'.length;    // 1
'あ'.length;   // 1

// 絵文字: サロゲートペア (2 つの UTF-16 コードユニット)
'😀'.length;   // 2 (!)
'👨‍👩‍👧‍👦'.length; // 11 (!!)

// ✅ 正しい文字数のカウント
[...'😀'].length;                    // 1
new Intl.Segmenter().segment('👨‍👩‍👧‍👦'); // 1 grapheme cluster

よくあるバグ

文字列の切り詰め

// ❌ サロゲートペアの途中で切れる
'Hello 😀 World'.slice(0, 7); // "Hello �" (壊れた文字)

// ✅ スプレッド構文で文字単位に分割
[...'Hello 😀 World'].slice(0, 7).join(''); // "Hello 😀"

正規表現

// ❌ . はサロゲートペアの半分にマッチ
/^.$/u.test('😀');  // true (u フラグが必要)
/^.$/.test('😀');   // false (u フラグなし)

u (Unicode) フラグを付けないと、正規表現が UTF-16 コードユニット単位で動作する。

正規化 (NFC / NFD)

同じ文字が異なるコードポイントの組み合わせで表現される場合がある。

const a = 'é';           // U+00E9 (合成済み)
const b = 'e\u0301';     // U+0065 + U+0301 (分解形)
a === b;                  // false (!)
a.normalize('NFC') === b.normalize('NFC'); // true

ファイル名やユーザー入力の比較では、normalize('NFC') で正規化してから比較する。

DynamoDB と Unicode

DynamoDB の文字列型は UTF-8 で保存される。ソートキーの辞書順ソートは UTF-8 のバイト順になるため、日本語のソート順が期待と異なる場合がある。

基礎から学ぶなら関連書籍が手がかりになる。

関連用語