見た目が同じでも、符号の並びが違うことがある
「が」をコピーして検索したのに、画面にある同じ「が」が見つからない。その原因の一つは、一つの符号の「が」と、「か+結合用の濁点」が別々の文字列として保存されていることです。Unicodeではこの二通りを正規等価な表現として扱いますが、アプリが単純に符号の並びを比較していると、そのままでは一致しません。
| 表現 | コードポイント | 個数 |
|---|---|---|
| 合成済みの「が」 | U+304C | 1 |
| 「か」+結合用濁点 | U+304B U+3099 | 2 |
表の二番目の濁点は、前の文字に組み合わせるためのU+3099です。単独で幅を持つ「゛」のU+309Bとは別の符号です。「濁点らしい形なら何を足しても同じになる」とは限りません。この違いは、文字を拡大するよりコードポイントを調べる方が確実に分かります。
正規化で、比較する形を揃える
Unicode正規化は、定められた等価関係に従って文字列の形を揃える処理です。NFCは正規分解の後に可能なものを合成し、NFDは正規分解した形にします。二つの「が」をそれぞれNFCにすれば、どちらもU+304Cになります。NFDなら、どちらもU+304B U+3099になります。比較する両側に同じ処理を適用することが要点です。
「Cだからいつも一符号になる」「Dだからすべての文字が細かい部品に分かれる」という意味ではありません。合成や分解の対応が定義されている文字だけが対象です。例えば、どんな漢字でも部首に分解してくれる仕組みではありません。
NFKCは便利だが、元の区別を失う
| 入力 | NFC | NFKC |
|---|---|---|
| か+結合用濁点 | が | が |
| A(全角のA) | A | A |
| ① | ① | 1 |
| ガ | ガ | ガ |
| ㎏ | ㎏ | kg |
| ² | ² | 2 |
NFKCとNFKDは、互換等価な文字も対象にします。全角英字や半角カタカナなどの揺れを吸収する検索には便利ですが、丸数字の丸、上付きという区別、単位記号のまとまりなどが失われます。数式や原文の忠実な保存に対して無条件に実行するべき処理ではありません。
例えば「x²」の上付き2を普通の2にすると、元の見た目が示していた指数の情報を、文字列だけからは復元できなくなります。検索用の正規化済みキーと、表示・保存用の原文を分ける設計が役立ちます。元の表記を後から復元する必要がある場合、変換後の文字列だけを残すのは避けましょう。
正規化で解決すること、しないこと
Unicode正規化は、似た形の文字を何でも同じにする処理ではありません。ラテン文字のOと数字の0、大文字と小文字、ひらがなとカタカナが一律に同じになるわけではありません。空白の除去、大小文字の扱い、異体字や表記揺れの扱いは、別の目的と規則を持つ処理です。
検索エンジンやデータベースによっては、照合規則の段階で濁点や文字幅などの違いを吸収します。逆に完全一致検索では、そのまま区別することがあります。「検索できない=必ずUnicode正規化が原因」と決めつけず、前後の空白、OCRの誤認識、別の文字種、検索オプションも確認します。
問題を切り分ける手順
最初に原文を保存し、一致しない部分だけを短く取り出します。コードポイントを比較して、U+304CとU+304B U+3099のような正規等価の違いかを確かめます。その場合はNFCなどに揃えて比較します。両方を同じ形式にしても一致しないなら、別の文字や空白の混入を調べます。
JavaScriptではString.prototype.normalizeが、NFC・NFD・NFKC・NFKDの各形式を扱います。ツール名だけで判断せず、採用する形式を明示することが重要です。パスワードや識別子など、サービス側に比較規則がある入力は、利用者が独自に正規化して変更せず、そのサービスの仕様に従ってください。
関連する雑記
参考資料
資料確認日:2026年10月2日
