使用 Unicode 正規化來表示字串

應用程式可以使用 Unicode 來代表多個表單中的字串。 由於 Unicode 接受已成長,特別是透過網際網路,因此需要消除 Unicode 字串中非必要的差異。 例如,當網頁伺服器回應頁面要求或連結器在程式庫中搜尋特定識別碼時,字元組合的多個標記法會使軟體複雜。

警告

不同的 Unicode 字串看起來可能完全相同,因此會引發安全性考慮。 如需詳細資訊,請參閱 安全性考慮:國際功能

 

為了因應這項需求,Unicode 聯盟已定義稱為「正規化」的程式,這會產生字元任何對等二進位標記法的一個二進位標記法。 一旦正規化,只有當兩個字串具有相同的二進位表示時,才相等。 正規化可消除一些差異,但會保留大小寫。

若要使用 Unicode 正規化,應用程式可以呼叫 NormalizeStringIsNormalizedString 函式,將字串重新排列為 Unicode 4.0 TR#15。 正規化可藉由減少具有相同語言意義的替代字串表示來協助改善安全性。 不過,請記住,正規化無法完全消除替代標記法。

如需標準化 Unicode 標準的詳細描述,請參閱 Unicode 標準附錄 #15:Unicode 正規化表單 (UAX #15) 。

警告

因為正規化可以變更字串的形式,所以通常應該在正規化之後實作安全性機制或字元驗證演算法。 如需詳細資訊,請參閱 安全性考慮:國際功能

 

提供相同字串的多個標記法

在許多情況下,Unicode 允許以語言方式表示相同字串的內容。 例如:

  • 大寫字母 A (umlaut) 可以表示為單一 Unicode 字碼指標 「Ä」 (U+00C4) 或大寫 A 的組合,以及合併 Dieresis 字元 (「A」 + 「ー」,也就是 U+0041 U+0308) 。 類似考慮適用于具有讀音符號的許多其他字元。
  • 大寫字母 A 本身可以用一般方式來表示, (拉丁大寫字母 A、U+0041) ,或以 Fullwidth Latin 大寫字母 A (U+FF21) 表示。 類似的考慮適用于另一個簡單的拉丁字母 (大寫和小寫) ,以及用於寫入日文的片假名字元。
  • 字串 「fi」 可以透過 「f」 和 「i」 (U+0066 U+0069) 或 ligature 「fi」 (U+FB01) 來表示。 類似的考慮適用于 Unicode 定義連字的許多其他字元組合。

使用四個定義的正規化表單

您的應用程式可以使用數種稱為「正規化形式」的演算法來執行 Unicode 正規化,以遵守不同的規則。 Unicode 聯盟已定義四種正規化形式:NFC (表單 C) 、NFD (表單 D) 、NFKC (格式 KC) ,以及 NFKD (表單 KD) 。 每個表單都會消除一些差異,但會保留大小寫。 Win32 和.NET Framework支援所有四種正規化形式。

NLS 列舉類型 NORM_FORM 支援四種標準 Unicode 正規化形式。 Form C 和 D 提供字串的正式形式。 非標準形式 KC 和 KD 提供進一步的相容性,而且可以顯示表單 C 和 D 中不明顯的特定語意等價。不過,它們會犧牲某些資訊損失,而且通常不應該做為儲存字串的正式方式。

在兩種標準表單中,表單 C 是「組成」表單,而表單 D 是「已分解」表單。 例如,表單 C 會使用單一 Unicode 字碼指標 「Ä」 (U+00C4) ,而表單 D 則使用 (「A」 + 「 Ė」,也就是 U+0041 U+0308) 。 這些轉譯方式完全相同,因為 「ー」 (U+0308) 是結合字元。 Form D 可以使用任意數目的代碼點來代表表單 C 所使用的單一字碼點。

如果兩個字串的格式為 C 或 form D 相同,則它們在其他形式中相同。 此外,正確轉譯時,它們會從彼此不區分顯示,以及從原始的非正規化字串顯示。

正規化之後,字串無法一致地傳回至其原始標記法。 例如,如果混合撰寫和分解字元表示的字串轉換成正規化形式,則無法將它取消正規化為原始混合字串。 因此,如果應用程式需要字串的原始標記法,則必須明確地儲存該標記法。 不過,在兩個標準表單之間轉換是可回復的。 格式 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,並說明四種正規化形式之間的差異。

原始 表單 D 表單 C 注意
「Äffin」 「A\u0308ffin」 「Äffin」 ffi_ligature (U+FB03) 未分解,因為它具有相容性對應,而不是標準對應。${REMOVE}$
「Ä\uFB03n」 「A\u0308\uFB03n」 「Ä\uFB03n」
「儲存區 IV」 「儲存區 IV」 「儲存區 IV」 羅馬數字 IV (U+2163) 未分解。${REMOVE}$
「系統 \u2163」 「系統 \u2163」 「系統 \u2163」
ga ka +ten ga 單一日文字元的不同相容性對等專案不會以 C.${REMOVE}$ 格式產生相同的字串
ka +ten ka +ten ga
hw_ka +hw_ten hw_ka +hw_ten hw_ka +hw_ten
ka +hw_ten ka +hw_ten ka +hw_ten
hw_ka +十 hw_ka +十 hw_ka +十
kaks k i + a m + ks f kaks 韓文音節會維持在正規化之下。

 

原始 表單 KD 表單 KC 注意
「Äffin」 「A\u0308ffin」 「Äffin」 ffi_ligature (U+FB03) 會以 KC 格式分解,但不是 C.${REMOVE}$ 格式
「Ä\uFB03n」 「A\u0308ffin」 「Äffin」
「儲存區 IV」 「儲存區 IV」 「儲存區 IV」 此處產生的字串格式為 KC.${REMOVE}$
「系統 \u2163」 「儲存區 IV」 「儲存區 IV」
ga ka +ten ga 單一日文字元的不同相容性對等專案會導致相同字串格式為 KC.${REMOVE}$
ka +ten ka +ten ga
hw_ka +hw_ten ka +ten ga
ka +hw_ten ka +ten ga
hw_ka +十 ka +ten ga
kaks k i + a m + ks f kaks 韓文音節會維持在正規化之下。 在舊版 Unicode 中,ks f 之類的 jamo 字元與 k f + s f具有相容性對應。 Unicode 2.1.9 已移除這些對應,以確保會維護韓文音節。

 

注意

上述兩個表格的著作權©為 1998-2006 Unicode, Inc.保留擁有權利。

 

針對單一字元使用 Composed Forms

對應至單一圖像的許多字元序列沒有組成表單。 即使以 C 格式正規化,單一視覺圖像或邏輯文字專案也可以由多個 Unicode 字碼點組成。 例如,在撰寫立陶宛文中使用的數個字元具有雙音符號,因為它們只有分解的表單。 例如,含有 macron 和 tilde (「ū̃」, U+016b U+0303 的小寫 U,其中第一個字碼點是具有 macron 的小寫 U,而第二個則是結合輔色) 。

範例

您可以在 NLS:Unicode 正規化範例中找到相關的範例。

使用國家語言支援

安全性考慮:國際功能

IsNormalizedString

NormalizeString