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 のバイト順になるため、日本語のソート順が期待と異なる場合がある。
基礎から学ぶなら関連書籍が手がかりになる。