Unicode正規化ツール

同じ見た目の文字列でも、アクセントが単一のコードポイントとして存在するか、文字に結合文字が付いた形かによって、異なるバイト列として保存されることがあります。この正規化ツールは、テキストを4つのUnicode正規化形式(NFC、NFD、NFKC、NFKD)の間で変換し、文字列がデータベース、検索インデックス、重複排除スクリプト、正規表現マッチで正しく比較されるようにします。

Unicodeテキストの正規化方法

  1. 1

    入力を貼り付ける

    文字列を入力します。アクセント付きの文字、CJKテキスト、合字など、一貫性がないと感じるものは何でも構いません。

  2. 2

    形式を選ぶ

    NFC(合成、一般的なWeb形式)、NFD(分解)、NFKC(互換合成)、NFKD(互換分解)から選びます。

  3. 3

    数値を比較する

    このツールは前後の文字数(コードポイント数)とバイト長を報告するので、形式によって文字列が短くなったか長くなったかを確認できます。

  4. 4

    正規化された出力をコピーする

    結果をデータベース、APIペイロード、スラグ生成、テストフィクスチャなどに使います。

4つの形式と、それぞれの使いどころ

Unicode正規化は標準附属書UAX #15で定義されています。4つの形式は2つの軸で異なります。正準か互換か、そして合成か分解かです。

一覧比較

形式 合成 マッピング 使う場面
NFC 合成 正準のみ Webコンテンツ、データベース、ファイル名の既定
NFD 分解 正準のみ 文字ごとにアクセントを除去するテキスト処理
NFKC 合成 互換を含む 検索、識別子、スパムフィルター、表示用の畳み込み
NFKD 分解 互換を含む 発音区別符号を除去する前の積極的な正規化

正準形は意味を保つ

é と入力して形式を切り替えてみてください。NFCは1文字・2バイトと報告し(単一のコードポイントU+00E9)、NFDは2文字・3バイトと報告します(素のeに結合用のアキュートアクセントU+0301が続いた形)。両者は画面上では同じに見えますが、バイト列は異なります。この食い違いこそ、正規化が解決するものです。正準形はバイトを並べ替えるだけなので、どちらの形式でもéは常にアキュートアクセント付きの e を意味します。

「互換性」が実際に変えるもの

K形式(NFKC、NFKD)は、似て見えても異なる書式を持つ文字も書き換えます。これは不可逆で、元には戻せません。たとえば:

  • fi(U+FB01、ラテン小文字合字 fi)は fi(2文字)になります
  • ①(U+2460、丸囲み数字の1)は 1 になります
  • ㌀(U+3300、CJKの正方形「アパート」)は アパート になります
  • 全角の A(U+FF21)は A になります

検索や重複排除には強力ですが、体裁には破壊的なので、K形式は見た目の忠実さが重要でないときにだけ使ってください。

実用的なルール

  • ユーザーコンテンツは NFC で保存します。
  • 識別子は NFC で比較し、単一コードポイントで書かれた café と、e + U+0301 で書かれた café が一致するようにします。fi と fi、全角の A と A も等しく比較したい場合は、UAX #31 の識別子規則と同様に NFKC に切り替えます。
  • 発音区別符号を取り除いたスラグは、NFD に正規化してから結合文字ブロック U+0300〜U+036F を削除して作ります。

よくある質問

たいていは、入力がすでに目的の形式だったということです。出所の異なるテキスト(Macのファイル名、コピーしたPDFの断片、古いデータベースの行)を混ぜて貼り付けると、文字数やバイト数が変化するのを見られる可能性がずっと高くなります。

表示用のURLにはNFCです。素のASCIIにしたいスラグでは、NFDに正規化し、U+0300〜U+036F を対象にした正規表現で結合文字を取り除いてから小文字にします。合字や丸囲み数字も畳み込みたい場合は、NFKDが代替になります。

正準形(NFC、NFD)は意味を変えず、バイトを並べ替えるだけです。互換形(NFKC、NFKD)は意味を変えます。合字は分割され、全角文字は畳み込まれ、上付き文字は平らになります。そうしたい場合にだけ使ってください。

正規化は当社サーバー上でPHPのNormalizerクラスを使って行われ、結果は同じリクエストで返されます。テキストは保存されません。記録するのはどの形式が適用されたかという匿名のイベントだけで、内容そのものは記録しません。

関連ツール

このツールは他の言語でも利用できます