ICUプロジェクト (これには PHPライブラリ もあります)には、検索時に値を比較しやすくするためにUTF-8文字列を正規化するのに必要なクラスが含まれています。
しかし、私は これが何を意味するか アプリケーションを理解しようとしています。たとえば、どのケースで「互換性等価性」ではなく「標準等価性」が必要ですか?
Unicodeには、いくつかの文字、特にアクセント付き文字をエンコードする複数の方法が含まれています。正準正規化は、コードポイントを正準エンコーディング形式に変更します。結果のコードポイントは、フォントまたはレンダリングエンジンのバグがない限り、元のコードポイントと同じように見えるはずです。
結果が同一に見えるため、入力とビットがまったく同一でない結果を許容できる限り、文字列を格納または表示する前に正規正規化を文字列に適用することは常に安全です。
正規化には、NFDとNFCの2つの形式があります。この2つは、これら2つの形式を損失なしに変換できるという意味で同等です。 NFCの下の2つの文字列を比較すると、常にNFDの下で比較した場合と同じ結果が得られます。
NFDの文字は完全に展開されています。これは計算が高速な正規化形式ですが、結果としてコードポイントが増えます(つまり、より多くのスペースを使用します)。
まだ正規化されていない2つの文字列を比較するだけの場合、互換性の正規化が必要なことがわかっていない限り、これが優先正規化形式です。
NFCは、NFDアルゴリズムの実行後、可能であればコードポイントを再結合します。これには少し時間がかかりますが、文字列が短くなります。
Unicodeには、実際には属していないが、レガシー文字セットで使用されていた多くの文字も含まれています。 Unicodeはこれらを追加して、これらの文字セットのテキストをUnicodeとして処理し、その後損失なしに変換できるようにしました。
互換性の正規化は、これらを「実際の」文字の対応するシーケンスに変換し、標準的な正規化も実行します。互換性の正規化の結果は、元のものと同一に見えない場合があります。
フォーマット情報を含む文字は、含まれない文字に置き換えられます。たとえば、文字_⁹
_は_9
_に変換されます。その他には、フォーマットの違いは関係しません。たとえば、ローマ数字の_Ⅸ
_は、通常の文字IX
に変換されます。
明らかに、この変換が実行されると、元の文字セットに可逆的に変換することはできなくなります。
Unicodeコンソーシアムは、ToUpperCase
変換のような互換性の正規化を考えることを提案しています。状況によっては役に立つかもしれませんが、単にそれを自由に適用するだけではいけません。
おそらく_9
_を検索して_⁹
_に一致させるため、優れたユースケースは検索エンジンです。
おそらくすべきではないことの1つは、互換性の正規化をユーザーに適用した結果を表示することです。
互換性の正規化形式には、NFKDとNFKCの2つの形式があります。 NFDとCの関係は同じです。
NFKCの文字列は本質的にNFCでも使用され、NFKDおよびNFDでも同じです。したがって、NFKD(x)=NFD(NFKC(x))
、およびNFKC(x)=NFC(NFKD(x))
など。
疑わしい場合は、正規正規化を使用してください。該当するスペース/速度のトレードオフに基づいて、または相互運用するものに必要なものに基づいて、NFCまたはNFDを選択します。
一部の文字、たとえばアクセント付きの文字(たとえば、é
)は2つの方法で表すことができます-単一のコードポイントU+00E9
または普通の文字とそれに続くアクセント記号U+0065 U+0301
。通常の正規化では、これらのいずれかを選択して常に表します(NFCの単一コードポイント、NFDの結合形式)。
複数の基本文字のシーケンスとマークの組み合わせで表現できる文字(たとえば、「s、下のドット、上のドット」と上にドットを置き、下にドットを置く、または既にドットの1つを持っている基本文字を使用する)の場合、NFDはまた、これらのいずれかを選択します(以下のように、最初に行きます)
互換性の分解には、「実際には」文字ではないが、レガシーエンコーディングで使用されたためである多くの文字が含まれます。通常の正規化はこれらを統合しません(往復の整合性を保持するため-レガシーエンコーディング(少数のベトナムエンコーディングを除く)が両方を使用しないため、これは結合フォームの問題ではありません)が、互換性の正規化は行います。東アジアの一部のエンコーディング(または半角/全角のカタカナとアルファベット)に表示される「kg」キログラム記号、またはMacRomanの「fi」合字のように考えてください。
詳細については、 http://unicode.org/reports/tr15/ を参照してください。
通常の形式(データベースではなくUnicode)は、主に(排他的に?)発音区別記号を持つ文字を処理します。 Unicodeは、U + 00C0、「Latin Capital A with Grave」など、一部の文字に「組み込み」発音区別符号を提供します。 「ラテンキャピタルA」(U + 0041)から「結合墓アクセント」(U + 0300)を使用して同じ文字を作成できます。つまり、2つのシーケンスが同じ結果の文字を生成しても、バイト単位で比較すると、完全に異なるものとして表示されます。
正規化は、それに対処する試みです。正規化は、すべての文字が同じ方法でエンコードされることを保証します(または少なくとも試行します)。必要に応じてすべて別個の結合発音区別符号を使用するか、可能な限り単一のコードポイントを使用します。比較の観点から見ると、実際に選択する多くの問題ではありません。ほとんどの正規化された文字列は、別の正規化された文字列と適切に比較されます。
この場合、「互換性」とは、1つのコードポイントが1つの文字に等しいと想定するコードとの互換性を意味します。そのようなコードがある場合は、おそらく互換性のある標準形式を使用する必要があります。直接述べたことは一度もありませんが、通常の形式の名前は、Unicodeコンソーシアムが発音区別符号を別々に組み合わせて使用することが望ましいと考えていることを意味します。これには、文字列内の実際の文字をカウントするためのより多くのインテリジェンスが必要です(また、文字列をインテリジェントに分割するなど)が、より汎用性があります。
ICUを最大限に活用している場合、正規の標準形式を使用する可能性があります。 (たとえば)コードポイントが文字に等しいと想定する独自のコードを作成しようとしている場合、おそらくそれを可能な限り頻繁に実現する互換性のある標準形式が必要です。
2つのUnicode文字列が標準的に同等である場合、文字列は実際には同じであり、異なるUnicodeシーケンスのみを使用します。たとえば、Äは文字ÄまたはAとofの組み合わせのいずれかを使用して表すことができます。
文字列の互換性が同等である場合、文字列は必ずしも同じではありませんが、一部のコンテキストでは同じである可能性があります。例えば。 ffはffと同じと見なすことができます。
そのため、文字列を比較する場合、互換性の等価性は実際の等価性ではないため、正規の等価性を使用する必要があります。
ただし、文字列のセットを並べ替える場合は、ほぼ同じであるため、互換性の同等性を使用するのが理にかなっています。
正規の等価性または互換性の等価性のどちらがより関連性があるかは、アプリケーションによって異なります。 ASCII文字列比較についての考え方はおおまかに標準的な等価性に対応していますが、Unicodeは多くの言語を表します。Unicodeがすべての言語を西ヨーロッパのASCIIのように扱うことができます。
図1および2 は、2種類の等価の良い例を提供します。互換性の同等性の下では、サブスクリプト形式とスーパースクリプト形式の同じ数字が同等に比較されるように見えます。しかし、筆記体のアラビア語の形式や回転した文字と同じ問題を解決できるかどうかはわかりません。
Unicodeテキスト処理の難しい真実は、アプリケーションのテキスト処理要件について深く考え、利用可能なツールでできる限り対処する必要があるということです。それはあなたの質問に直接対処するものではありませんが、より詳細な答えには、サポートする予定の各言語の言語専門家が必要になります。
これは実際には非常に簡単です。 UTF-8には、実際には同じ「文字」のいくつかの異なる表現があります。 (バイト単位で異なるため、引用符で文字を使用しますが、実際には同じです)。リンクされたドキュメントに例を示します。
文字「Ç」は、バイトシーケンス0xc387として表すことができます。ただし、C
(0x43)の後にバイトシーケンス0xcca7を続けて表すこともできます。したがって、0xc387と0x43cca7は同じ文字であると言えます。動作する理由は、0xcca7が結合マークだからです。つまり、その前の文字(ここではC
)を受け取り、それを変更します。
ここで、標準的な等価性と互換性の等価性の違いに関しては、一般的な文字を調べる必要があります。
valueで意味を伝える文字と、別の文字を受け取って変更する文字の2種類の文字があります。 9は意味のあるキャラクターです。スーパースクリプトAはその意味を取り、プレゼンテーションによってそれを変更します。そのため、標準的には異なる意味を持ちますが、それでも基本文字を表しています。
正規の等価性とは、バイトシーケンスが同じ文字を同じ意味でレンダリングすることです。互換性の等価性とは、バイトシーケンスが同じベースの意味を持つ別の文字をレンダリングしている場合です(変更されている場合でも)。 9とTheは両方とも「9」を意味するため互換性は同等ですが、同じ表現を持たないため標準的には同等ではありません。
compare stringの問題:ほとんどのアプリケーションの目的に相当するコンテンツを持つ2つの文字列には、異なる文字シーケンスが含まれる場合があります。
nicodeの正準等価 を参照してください。比較アルゴリズムが単純な(または高速でなければならない)場合、 nicode等価 は実行されません。この問題は、たとえば、XMLの正規比較で発生します。 http://www.w3.org/TR/xml-c14n を参照してください
この問題を回避するには...どの標準を使用しますか? 「拡張UTF8」または「コンパクトUTF8」?
「ç」または「c +◌̧」を使用しますか?
W3Cなど(例: ファイル名 )は、「正規の構成」として使用することを提案します(「最もコンパクトな」短い文字列のCを考慮してください)...
相互運用性、および 「設定より規約」の選択肢 の場合、推奨は[〜#〜] nfc [〜#〜]の使用です。外部文字列を「正規化」します。たとえば、正規のXMLを保存するには、「FORM_C」に保存します。 W3Cの WebワーキンググループのCSVもNFCを推奨 (セクション7.2)。
PS:de "FORM_C"は、ほとんどのライブラリでデフォルト形式です。例 PHPのnormalizer.isnormalized()で 。
「compostion form」(FORM_C
)という用語は両方に使用され、「文字列はC正規形式である」(NFCの結果) _変換)および変換アルゴリズムが使用されると言うには... http://www.macchiato.com/unicode/nfc-faq を参照してください
(...)次の各シーケンス(最初の2つは単一文字シーケンスです)は、同じ文字を表します。
- U + 00C5(Å)ローマ字大文字Aリング付き
- U + 212B(Å)角のサイン
- U + 0041(A)ローマ字大文字A + U + 030A(̊)上記の組み合わせリング
これらのシーケンスは、標準的に同等と呼ばれます。これらの形式の最初はNFCと呼ばれます。正規化形式Cでは、Cはcompostionを表します。 (...)文字列SをNFC形式に変換する関数は
toNFC(S)
と省略できますが、SがNFCにあるかどうかをテストする関数は次のように省略できます。isNFC(S)
。
注:小さな文字列(純粋なUTF-8またはXMLエンティティ参照)の正規化をテストするには、 this test/normalize online converter を使用できます。