JavaScriptで同じ文字なのに一致しない?normalizeのNFC・NFKCを使い分ける

  • 公開:2026.10.05
  • 更新:2026.10.05
  • 開発
JavaScriptで同じ文字なのに一致しない?normalizeのNFC・NFKCを使い分ける

入力した名前は同じに見えるのに、JavaScriptの比較で一致しない。コピーした文字だけ検索に引っかからない。そんなときは、文字の見た目だけでなく、内部のUnicodeの並びを調べると手がかりが得られます。

たとえば「が」は、1つのコードポイントでも、「か」と結合濁点の組み合わせでも表せます。ここではString.prototype.normalize()で比較用の文字列をそろえる方法と、NFC・NFKCを選ぶときの注意点を紹介します。


一致しない文字列を比べる

次のコードは、JavaScriptを実行できるブラウザーの開発者ツールやNode.jsで試せます。\u304CなどはUnicodeのエスケープ表記です。「が」と「か+結合濁点」は同じように表示されても、元の文字列の並びは異なります。

const composed = "\u304C";    // が
const decomposed = "\u304B\u3099"; // か + 結合濁点

console.log(composed === decomposed);
console.log(composed.length, decomposed.length);
console.log(composed.normalize("NFC") === decomposed.normalize("NFC"));
false
1 2
true

最初の比較はfalseです。lengthも1と2に分かれます。両方をNFCで正規化すると、正準等価な表現がそろい、最後の比較はtrueになります。表示フォントによる字形の差と、文字列としての一致は別の問題です。

比較用の値をNFCでそろえる

NFCは、正準分解した後、可能な組み合わせを合成する正規化形式です。結合濁点を含む文字列の比較では、片方だけではなく、入力値と比較先の両方に同じ形式を適用すると結果をそろえられます。引数を省略したnormalize()もNFCですが、形式を明示しておくと意図が読み取りやすくなります。

const original = "か\u3099く";
const searchKey = original.normalize("NFC");

console.log(original.length);
console.log(searchKey);
console.log(searchKey.length);
console.log(original === searchKey);
3
がく
2
false

normalize()は新しい文字列を返します。この例ではoriginalをそのまま残し、searchKeyを比較用に作っています。氏名や表示名の表記を保持したい場合は、表示・保存する原文と検索用の値を分ける設計が役立ちます。

正規化後に文字列の長さが変わることもあります。入力上限を判定するタイミングと数える単位は、サーバー側とそろえる必要があります。絵文字や結合文字の文字数は、JavaScriptの文字数判定と切り詰めで具体例を紹介しています。

NFKCで変わる表記を確かめる

NFKCは互換分解も使うため、全角英字や丸数字などの表記が変わります。検索で表記の幅を吸収したい場合に使えますが、原文の区別が必要な欄へ一律に適用すると、残したかった情報が失われることがあります。

for (const text of ["ABC", "①", "髙", "高", "𠮷", "吉"]) {
  console.log(text, text.normalize("NFC"), text.normalize("NFKC"));
}
ABC ABC ABC
① ① 1
髙 髙 髙
高 高 高
𠮷 𠮷 𠮷
吉 吉 吉

この例では、NFKCによって「ABC」は「ABC」、「①」は「1」になります。一方、「髙」と「高」、「𠮷」と「吉」は同じ文字列にはなりません。正規化だけで、見た目の似た漢字や異体字をすべて統一できるわけではありません。

氏名では、本人が入力した表記を大切にしながら、どの違いを検索時に同一視するかを決める必要があります。保存先で「𠮷」が欠落する場合は、正規化で置き換える前に、文字コード・フォント・DBの対応を調べると原因を絞り込めます。

入力欄の目的に合わせて形式を選ぶ

目的 検討する形式・扱い
結合文字の表現差をそろえて比較する 両方の比較用値をNFCで正規化する
全角英字などの表記差を検索で吸収する NFKCの変換例を確認し、検索用の値で採用を判断する
氏名・表示名の入力表記を残す 原文を保持し、必要に応じて比較用の値を別に作る

NFCやNFKCは、大文字・小文字の統一、前後の空白除去、HTMLの安全な表示まで行う機能ではありません。それらも必要な場合は、入力欄ごとの仕様として別に設計してください。パスワードや署名検証の対象へ正規化を追加すると照合仕様が変わるため、既存の認証処理へそのまま組み込む用途には向きません。

仕様を確認するための資料

このブラウザからの自分のアクセスを解析から除外できます。