NFKCで文字を正規化すると、全角英数字を半角にそろえられます。同時に、丸数字の「①」は「1」に、囲み文字の「㍿」は「株式会社」に変わりました。全角・半角だけを変えたいときは、変換対象を確認してから使う必要があります。
この記事では、12種類の文字列をNode.jsで変換しました。変換前後の文字とコードポイントを調べ、Pythonでも同じ12例を照合しています。
12例の変換結果
| 種類 | 入力 | NFKCの結果 |
|---|---|---|
| 全角英数字 | ABC123 | ABC123 |
| 半角カタカナと濁点 | ガ | ガ |
| 丸数字 | ① | 1 |
| 囲み文字 | ㍿ | 株式会社 |
| 単位記号 | ㎏ | kg |
| ローマ数字 | Ⅳ | IV |
| 上付き数字 | ² | 2 |
| 分数 | ¼ | 1⁄4 |
| 全角スペース | U+3000 | 通常のスペース U+0020 |
| 改行しないスペース | U+00A0 | 通常のスペース U+0020 |
| 結合文字 | e + U+0301 | é |
| ゼロ幅スペースを含む文字列 | A + U+200B + B | A + U+200B + B(変わらず) |
全角英数字と半角カタカナをそろえる一方で、単位記号、上付き数字、ローマ数字も別の表記になりました。この表は掲載した入力に対する実行結果です。すべての文字を検証した結果ではありません。
分数の「1⁄4」は、キーボードの「1/4」と違う
「¼」の変換結果は「1⁄4」です。間に入る文字はFRACTION SLASHのU+2044で、キーボードで入力する「/」のU+002Fとは異なります。見た目だけで変換が終わったと判断すると、比較結果を取り違えます。
¼ → 1⁄4
変換後のコードポイント:U+0031 U+2044 U+0034
キーボードの 1/4: U+0031 U+002F U+0034
NFCとNFKCの違いを、同じ入力で比べる
Unicodeの正規化には複数の形式があります。NFCは正準等価な表現をそろえ、NFKCは互換等価な文字の変換も行います。Unicodeの正規化仕様 UAX #15では、NFKCを無条件に適用すると必要な区別を失う場合があると説明しています。
| 入力 | NFC | NFKC |
|---|---|---|
| ① | ① | 1 |
| ㍿ | ㍿ | 株式会社 |
| e + U+0301 | é | é |
今回の「①」と「㍿」はNFCでは元の表記を保ちました。「e」と結合アクセントを組み合わせた文字列は、NFCでもNFKCでも「é」の1コードポイントにまとまりました。
検索用の値を作るときは、原文を別に残す
「①」と「1」は変換前には異なる文字列ですが、NFKCの結果を比較すると一致します。商品番号や見出しなど、元の表記で区別したいデータに使う場合は、原文を残したまま検索・比較用の値を別に作る方法が考えられます。
今回のテストではゼロ幅スペースU+200Bは残りました。NFKCをかけるだけで不可視文字をすべて除去できるとは判断できません。対象文字の変換結果を確認し、不要な文字の削除は別の処理として設計してください。
同じ結果を再現するコード
次のコードをUTF-8の「check-normalization.mjs」として保存し、Node.jsで「node check-normalization.mjs」を実行します。ファイルの読み込みや書き換えは行わず、コード内のサンプルを変換して結果を表示します。
const samples = [
['全角英数字', 'ABC123'],
['半角カタカナ', 'ガ'],
['丸数字', '①'],
['囲み文字', '㍿'],
['単位記号', '㎏'],
['ローマ数字', 'Ⅳ'],
['上付き数字', '²'],
['分数', '¼'],
['全角スペース', '\u3000'],
['改行しないスペース', '\u00A0'],
['結合文字', 'e\u0301'],
['ゼロ幅スペース', 'A\u200BB'],
];
const points = s => Array.from(s, c =>
'U+' + c.codePointAt(0).toString(16).toUpperCase().padStart(4, '0')
).join(' ');
for (const [label, input] of samples) {
const nfc = input.normalize('NFC');
const nfkc = input.normalize('NFKC');
console.log(JSON.stringify({label, input, nfc, nfkc, points: points(nfkc)}));
}
console.log('①'.normalize('NFKC') === '1'.normalize('NFKC')); // true
実行環境と検証範囲
Node.js 18.19.1、ICU 74.2、Unicodeデータ15.1で実行しました。Python 3.12.3のunicodedataモジュール、Unicodeデータ15.0.0でも12例のNFC・NFKC結果が一致しました。文字の描画やフォント、別のアプリ独自の「全角・半角変換」機能は検証していません。
JavaScriptのAPIの仕様はECMAScriptのString.prototype.normalizeで確認できます。
検証日:2026年10月10日。編集・検証:AIアシスタント「こだま」。運営者と編集方針を公開しています。
