使用 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 的組合,以及大寫 A 的組合字元 (「A」 + 「ー」,也就是 U+0041 U+0308) 。 類似考慮適用于具有讀音符號的許多其他字元。
  • 大寫字母 A 本身可以透過一般方式來表示 (拉丁大寫字母 A、U+0041) ,或透過 Fullwidth Latin Capital Letter 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 正規化形式。 表單 C 和 D 提供字串標準形式。 非標準形式 KC 和 KD 提供進一步的相容性,而且可以顯示表單 C 和 D 中不明顯的特定語意等號。不過,它們會犧牲特定資訊損失,通常不應該當做儲存字串的規範方式使用。

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

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

正規化之後,字串無法一致地傳回其原始標記法。 例如,如果混合撰寫和分解字元表示的字串轉換成正規化形式,則沒有任何方法可將它取消正規化為原始的混合字串。 因此,如果應用程式需要字串的原始標記法,則必須明確地儲存該標記法。 不過,在兩個標準形式之間轉換是可復原的。 表單 C 中的字串可以轉換成 form D,然後回到表單 C,而結果與原始表單 C 字串相同。

表單 KC 和 KD 分別與表單 C 和 D 類似,但這些「相容性表單」具有與每個字元基本形式的其他相容字元對應。 這類對應可能會導致次要字元變化遺失。 它們會結合視覺上相異的特定字元。 例如,它們結合了全形和半形字元與相同的語意意義,或相同阿拉伯文字母的不同形式,或是 U+FB01 (U+FB01) 和字元組 「fi」 (U+0066 U+0069) 。 它們也會結合某些可能具有不同語意意義的字元,例如以上標撰寫的數位、下標或以圓形括住的數位。 由於這項資訊遺失,通常不應該將 KC 和 KD 形式當做標準形式的字串使用,但對於某些應用程式而言很有用。

表單 KC 是組成表單,而表單 KD 是已分解的表單。 即使原始字串的格式為 C 或 D,應用程式可以在表單 KC 與 KD 之間來回,但無法一致的方式從表單 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」 ROMAN NUMBER 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