AIに文字列の正規化コードを作らせる方法|NFC・NFKCと同じ値になる候補を確認

架空ラベル10件でPythonのNFC・NFKCを比較。全角・半角、丸数字、結合文字、記号、空白を検査し、元の値と同じ比較キーになる候補を保持します。

AIものさし編集部

AIに文字列の整形コードを作らせるときは、「表記ゆれを直す」を具体的な変換へ分けます。全角・半角をそろえる、結合文字を整える、空白を削る、大文字へ変えることは、同じ処理ではありません。まとめて実行すると、区別していた値まで同じになる場合があります。

この記事では、架空のラベル10件をPythonでNFC・NFKCへ正規化し、元の値と結果を並べます。AIが生成したコードや実台帳の処理結果ではありません。行を削除・統合せず、比較キーが重なる箇所を確認する例です。

NFCとNFKCを、見た目の統一だけで選ばない

Unicodeは、正規等価と互換等価に基づく正規化を区別しています。NFCは正規分解と合成、NFKCは互換分解と合成を使うため、NFKCでは全角・半角などの区別が折りたたまれる場合があります。意味に必要な区別を失う可能性もあるので、任意の文章へ無条件に適用しません。Unicode:正規化形式(新しいタブで開く)

ここでは、どちらが優れているかを決めず、同じ入力に対する差を調べます。正式名称や識別子へ何を許すかは、その列の定義へ戻ります。文章を読みやすくする依頼と、システムが照合するキーの変更を一緒に確定しないようにしてください。

表は横にスクロールできます

最初に決めること今回の扱い
元の値original列を保持する
比較する変換NFC、NFKCを別列にする
空白処理前後空白を削らない
大小文字変換しない
似た記号の置換独自の置換を追加しない
同じ結果の行候補として表示し、削除しない

見た目が近い入力を、コードポイントで区別する

次の10件は、実際の品番や顧客名ではない架空のラベルです。R06は「カ+結合濁点+イ+ト+結合濁点」で作ります。R07の「ガイド」と似て見えても、正規化前の文字列は異なります。

表は横にスクロールできます

ID入力の説明NFCの結果NFKCの結果
R01ABC-123ABC-123ABC-123
R02ABC-123ABC-123ABC-123
R03部品①部品①部品1
R04部品1部品1部品1
R05ガイドガイドガイド
R06カ+U+3099+イ+ト+U+3099ガイドガイド
R07ガイドガイドガイド
R08ABC−123。区切りはU+2212ABC−123ABC−123
R09「ABC-123 」の末尾に空白1文字末尾空白が残る末尾空白が残る
R10abc-123abc-123abc-123

R03の丸数字は、NFKCでは通常の数字へ変わります。それがこの列で許されるかは別判断です。「部品①」と「部品1」が別の正式ラベルなら、比較キーが同じだからという理由で原文を統一できません。

R08のマイナス記号は、この例ではASCIIハイフンへ変わりません。NFKCを使えば似た記号がすべて同じになる、と考えないでください。末尾空白の除去や小文字の大文字化も、今回の正規化だけでは行っていません。

元の列を残す小さなコードで試す

Pythonのunicodedata.normalizeでは、形式名と文字列を指定できます。使用したPythonとUnicodeデータの版も記録します。Python公式:unicodedata(新しいタブで開く)

import unicodedata

rows = [
    ("R01", "ABC-123"),
    ("R02", "ABC-123"),
    ("R03", "部品①"),
    ("R04", "部品1"),
    ("R05", "ガイド"),
    ("R06", "カ\u3099イト\u3099"),
    ("R07", "ガイド"),
    ("R08", "ABC\u2212123"),
    ("R09", "ABC-123 "),
    ("R10", "abc-123"),
]

result = [
    {
        "row_id": row_id,
        "original": text,
        "nfc": unicodedata.normalize("NFC", text),
        "nfkc": unicodedata.normalize("NFKC", text),
    }
    for row_id, text in rows
]
print("Unicode data:", unicodedata.unidata_version)
for item in result:
    print(item["row_id"], repr(item["original"]), repr(item["nfkc"]))

このコードは正規化結果を別の値として持ち、元の文字列を上書きしません。今回の10件はローカルで実行し、上の変換表と一致しました。出力を見て区別しにくい文字は、Unicodeのコードポイントも記録すると確認しやすくなります。

例えばR06の元の文字列には、U+3099が2か所含まれます。見た目だけで「同じ文字列だった」と判断せず、比較した値と使った形式を残します。フォントや画面での見え方を、このコードで検証したわけではありません。

同じ比較キーへ変わった行をまとめて確認する

今回のNFKC結果では、次の3グループが同じ値になります。

表は横にスクロールできます

比較キー元の行IDこの例から分かること
ABC-123R01、R02全角とASCIIの差がなくなる
部品1R03、R04丸数字の区別がなくなる
ガイドR05、R06、R07半角表記や結合文字の差がまとまる

元の文字列は10種類あり、NFKC後の異なる値は6種類です。ただし、行は10件のまま残します。比較キーが同じになる候補3グループ・7行を見つけたことと、4件を削除してよいことは同じではありません。

NFCでは、この例の変化はR06だけで、異なる値は9種類です。どちらの変換でも、結果が同じになった行を実世界の同じ品目・人物・会社と認定したことにはしません。

元の値と変換後の値、変換形式、変化の有無、同じ結果のグループを残して担当者へ渡します。正式名称を変更するのか、検索用の補助列だけに使うのかも分けて決めます。

AIへ、追加の置換を勝手に混ぜないよう指定する

文字列正規化の確認コードを作ってください。
環境:[言語・ライブラリ・バージョン]。
originalとrow_idを保持し、NFCとNFKCの結果を別列へ出してください。
空白除去、大小文字変換、似た記号の独自置換を追加しないでください。
変化した行と、変換後に同じ値になる行IDを示してください。
同じ結果になっても削除・統合せず、確認用の候補にしてください。
出力件数が入力件数と一致することを検査してください。
正式名称や同一人物かどうかは、この変換だけで確定しないでください。
見分けにくい文字は、元と変換後のコードポイントも示してください。
実行していなければ、実測した結果として説明しないでください。
入力:[必要な文字列と行ID]

空欄や欠損値を含む実データでは、文字列への変換規則も決めます。欠損値を「None」などの文字へ変えた結果が、実際のラベルと混ざることを避けます。今回のコードは10件すべてが文字列の例で、欠損処理まで実装した汎用クレンジングではありません。

空白除去や大小変換も必要なら、正規化とは別の段階として結果を記録し、その段階で新しく同じになる値を確認します。NFKCだけの検査が通ったことを、後から追加した変換の検査へ使い回さないでください。

正規化の完了と、台帳整理の完了を分ける

正規化は文字列の表現をそろえる処理であり、値の正しさや同一性を確認する仕組みではありません。識別子なら仕様上どの表記を許すか、名称なら原資料をどう保持するかへ戻ります。

CSVの削除規則と件数の管理は、CSVの重複行を整理する方法で扱います。顧客の同一性を判断する場合は、顧客台帳の表記ゆれ・重複整理へ進みます。今回の成果物は、変換で何が変わり、どの値が同じになったかを追える確認表です。

参考資料

公式仕様の確認日:2026年10月20日。ラベル10件は架空例で、Pythonコードをローカルで実行しました。AI生成、実台帳の同一性、正式名称の採用、他の実装環境、フォント・画面表示は検証していません。

質問から自分に合うAIを探す