Unicode 正規化を使用して文字列を表す

アプリケーションでは、Unicode を使用して複数の形式の文字列を表すことができます。 特にインターネット経由で Unicode の受け入れが増えるにつれて、Unicode 文字列の本質的でない違いを排除する必要性が生じていました。 文字の組み合わせに対して複数の表現を使用すると、Web サーバーがページ要求に応答したり、リンカーがライブラリ内の特定の識別子をシークしたりする場合など、ソフトウェアが複雑になります。

注意事項

異なる Unicode 文字列は視覚的に同一のように見え、セキュリティ上の懸念が高まる可能性があります。 詳細については、「 セキュリティに関する考慮事項: 国際機能」を参照してください。

 

この要件に応じて、Unicode コンソーシアムは"正規化" と呼ばれるプロセスを定義しました。これにより、文字の同等のバイナリ表現のいずれかに対して 1 つのバイナリ表現が生成されます。 正規化されると、2 つの文字列が同じバイナリ表現を持つ場合にのみ、2 つの文字列が等価になります。 正規化により、いくつかの違いはなくなりますが、大文字と小文字は保持されます。

Unicode 正規化を使用するために、アプリケーションは NormalizeString 関数と IsNormalizedString 関数を呼び出して、Unicode 4.0 TR#15 に対応する文字列を再配置できます。 正規化は、同じ言語的意味を持つ代替文字列表現を減らすことで、セキュリティを向上させるのに役立ちます。 ただし、正規化では代替表現を完全に排除できないことに注意してください。

正規化の Unicode 標準の詳細については、「 Unicode 標準の付属書 #15: Unicode 正規化フォーム (UAX #15)」を参照してください。

注意事項

正規化によって文字列の形式が変更される可能性があるため、通常、セキュリティ メカニズムまたは文字検証アルゴリズムは正規化後に実装する必要があります。 詳細については、「 セキュリティに関する考慮事項: 国際機能」を参照してください。

 

同じ文字列の複数の表現を指定する

多くの場合、Unicode では、言語的に同じ文字列を複数表現できます。 次に例を示します。

  • 二角かっこ (ウムラウト) を含む大文字 A は、単一の Unicode コード ポイント "Ä" (U+00C4) または大文字 A と結合された二角かっこ文字 ("A" + "̈"、つまり U+0041 U+0308) の組み合わせとして表すことができます。 同様の考慮事項は、分音記号を持つ他の多くの文字にも適用されます。
  • 大文字 A 自体は、通常の方法 (英大文字 A、U+0041) または Fullwidth Latin Capital Letter A (U+FF21) で表すことができます。 同様の考慮事項は、他の単純なラテン文字 (大文字と小文字の両方) と、日本語の記述で使用されるカタカナ文字にも適用されます。
  • 文字列 "fi" は、文字 "f" と "i" (U+0066 U+0069) または合字 "fi" (U+FB01) で表すことができます。 同様の考慮事項は、Unicode が合字を定義する他の多くの文字の組み合わせにも適用されます。

4 つの定義された正規化フォームを使用する

アプリケーションでは、さまざまな規則に従う "正規化フォーム" と呼ばれるいくつかのアルゴリズムを使用して Unicode 正規化を実行できます。 Unicode コンソーシアムでは、NFC (フォーム C)、NFD (フォーム D)、NFKC (フォーム KC)、NFKD (KD フォーム) の 4 つの正規化形式が定義されています。 各フォームではいくつかの違いはありませんが、大文字と小文字は保持されます。 Win32 と .NET Framework では、4 つの正規化フォームがすべてサポートされます。

NLS 列挙型 NORM_FORM では、4 つの標準 Unicode 正規化形式がサポートされています。 フォーム C と D は、文字列の正規形式を提供します。 非正規形式 KC と KD は、さらなる互換性を提供し、フォーム C と D では明らかではない特定のセマンティック等価性を明らかにできます。ただし、一定の情報損失を犠牲にして行います。一般に、文字列を格納する正規の方法として使用しないでください。

2つの正規形態のうち、形態Cは「構成される」形態であり、形態Dは「分解された」形態である。 たとえば、フォーム C では単一の Unicode コード ポイント "Ä" (U+00C4) が使用され、フォーム D では ("A" + "̈"、つまり U+0041 U+0308) が使用されます。 "̈" (U+0308) は結合文字であるため、これらは同じようにレンダリングされます。 フォーム D では、任意の数のコード ポイントを使用して、フォーム C で使用される 1 つのコード ポイントを表すことができます。

2 つの文字列がフォーム C またはフォーム D で同一の場合、もう一方の形式では同じです。 さらに、正しくレンダリングされると、互いに区別されずに、元の正規化されていない文字列から表示されます。

正規化されると、文字列を元の表現に一貫して返すことはできません。 たとえば、構成された文字表現と分解された文字表現が混在する文字列が正規化された形式に変換された場合、元の混合文字列に正規化を解除する方法はありません。 したがって、アプリケーションで文字列の元の表現が必要な場合は、その表現を明示的に格納する必要があります。 ただし、2 つの正規形間の変換は元に戻すことができます。 C 形式の文字列は、フォーム D に変換してから、フォーム C に戻すことができます。結果は元の形式の C 文字列と同じです。

フォーム KC と KD はそれぞれフォーム C と D に似ていますが、これらの "互換性フォーム" には、互換性のある文字と各文字の基本形式のマッピングが追加されています。 このようなマッピングにより、軽微な文字のバリエーションが失われる可能性があります。 これらは、視覚的に異なる特定の文字を組み合わせます。 たとえば、全角文字と半角文字と、同じ意味の意味を持つ文字、同じアラビア文字の異なる形式、合字 "fi" (U+FB01) と文字ペア "fi" (U+0066 U+0069) を組み合わせます。 また、上付き文字として書かれた数字、下付き文字、円で囲まれた数字など、セマンティックの意味が異なる場合がある文字も組み合わせます。 この情報損失のため、フォーム KC と KD は通常、文字列の正規形式として使用しないでくださいが、特定のアプリケーションに役立ちます。

KC形はKDが分解された形態と構成される形態である。 アプリケーションは、フォーム KC と KD の間でやり取りできますが、元の文字列が C または D の形式であっても、フォーム KC または KD から元の文字列に戻す一貫した方法はありません。

Windows、Microsoft アプリケーション、および .NET Frameworkは通常の入力メソッドを使用して C 形式の文字を生成します。 Windows のほとんどの目的で、フォーム C が推奨される形式です。 たとえば、C 形式の文字は Windows キーボード入力によって生成されます。 ただし、Web やその他のプラットフォームからインポートされた文字は、他の正規化形式をデータ ストリームに導入できます。

次の例は UAX #15 から作成され、4 つの正規化形式の違いを示しています。

変更元 フォーム D フォーム C メモ
"Äffin" "A\u0308ffin" "Äffin" ffi_ligature (U+FB03) は、標準マッピングではなく互換性マッピングを持っているため、分解されません。${REMOVE}$
"Ä\uFB03n" "A\u0308\uFB03n" "Ä\uFB03n"
"Henry IV" "Henry IV" "Henry IV" ローマ数字 IV (U+2163) は分解されません。${REMOVE}$
"Henry \u2163" "Henry \u2163" "Henry \u2163"
ga ka +10 ga 1 つの日本語文字に対応する互換性が異なると、C.${REMOVE}$ 形式の同じ文字列が生成されません。
ka +10 ka +10 ga
hw_ka +hw_ten hw_ka +hw_ten hw_ka +hw_ten
ka +hw_ten ka +hw_ten ka +hw_ten
hw_ka +10 hw_ka +10 hw_ka +10
kaks k i + a m + ks f kaks ハングル音節は正規化の下で維持されます。

 

変更元 フォーム KD Form KC メモ
"Äffin" "A\u0308ffin" "Äffin" ffi_ligature (U+FB03) は KC 形式で分解されますが、C.${REMOVE}$ の形式では分解されません
"Ä\uFB03n" "A\u0308ffin" "Äffin"
"Henry IV" "Henry IV" "Henry IV" ここで生成される文字列は KC.${REMOVE}$ の形式で同じです
"Henry \u2163" "Henry IV" "Henry IV"
ga ka +10 ga 1 つの日本語文字と同等の互換性が異なると、KC.${REMOVE}$ という形式の同じ文字列になります。
ka +10 ka +10 ga
hw_ka +hw_ten ka +10 ga
ka +hw_ten ka +10 ga
hw_ka +10 ka +10 ga
kaks k i + a m + ks f kaks ハングル音節は正規化の下で維持されます。 以前の Unicode バージョンでは、ks f のような jamo 文字には、k f + s f への互換性マッピングがありました。 これらのマッピングは、ハングル音節が維持されるように Unicode 2.1.9 で削除されました。

 

注意

上記の 2 つの表には、1998 年から 2006 年の Unicode, Inc. の著作権©があります。すべての権利予約済み。

 

1 つのグリフに構成済みフォームを使用する

1 つのグリフに対応する多くの文字シーケンスには、構成されたフォームがありません。 フォーム C によって正規化された場合でも、1 つのビジュアル グリフまたは論理テキスト要素を複数の Unicode コード ポイントで構成できます。 たとえば、リトアニア語の記述で使用される複数の文字は、分解された形しかないため、二重の分音記号を持っています。 たとえば、小文字の U とマクロとチルダ ("ū̃"、U+016b U+0303) です。最初のコード ポイントはマクロと小文字の U で、2 番目のコード ポイントは鋭いアクセントを組み合わせたものになります。

関連する例は、「 NLS: Unicode 正規化サンプル」で確認できます。

各国語サポートの使用

セキュリティに関する考慮事項: 国際的な機能

IsNormalizedString

NormalizeString