共用方式為


使用 Unicode 正規化來表示字串

應用程式可以使用 Unicode 來代表多個形式的字串。 隨著 Unicode 接受率的成長,特別是透過因特網,需要消除 Unicode 字串中的非基本差異。 例如,當網頁伺服器回應頁面要求或連結器在文檔庫中搜尋特定標識碼時,字元組合的多個表示法會使軟體複雜化。

謹慎

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

 

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

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

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

謹慎

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

 

提供相同字串的多個表示法

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

  • 大寫字母 A 與變音符號(umlaut)可以表示為單一的 Unicode 碼位 “Ä” (U+00C4),或者表示為大寫 A 與組合用變音符號(“A” + “¨”,也就是 U+0041 U+0308) 的結合。 類似的考量也適用於許多帶有附加符號的其他字符。
  • 大寫字母 A 本身可以以一般方式表示(拉丁大寫字母 A、U+0041)或全維德拉丁大寫字母 A (U+FF21)。 類似的考慮適用於其他簡單的拉丁字母(大寫和小寫),以及在書寫日語中使用的片假名字符。
  • 字串 “fi” 可以透過字元 “f” 和 “i” (U+0066 U+0069) 或韌帶 “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 是「分解」形式。 例如,表單C 使用單一 Unicode 字碼點 “Ä” (U+00C4),而表單D 則使用 (“A” + “¨”,即 U+0041 U+0308)。 這些呈現方式相同,因為 "¨"(U+0308) 是結合字元。 表單 D 可以使用任意數目的程式代碼點來代表表單 C 所使用的單一字碼點。

如果兩個字串在形式 C 或形式 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)未分解,因為它具有相容性映射,而不是正規映射。
Ä\uFB03n “A\u0308\uFB03n” “Ä\uFB03n”
“Henry IV” “Henry IV” “Henry IV” 羅馬數位 IV (U+2163) 未分解。${REMOVE}$
“亨利·\u2163” “亨利·\u2163” “亨利·\u2163”
加語 ka +ten 加語 單一日文字符的不同相容性對等專案不會以 C.${REMOVE}$ 格式產生相同的字串
ka +ten ka +ten 加語
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 +10 hw_ka +十
kaks k i + a ₘ + ks f kaks 韓文字母在正規化過程中保持不變。

 

原本 表單 KD 表單 KC 筆記
“Äffin” A\u0308ffin “Äffin” ffi_ligature (U+FB03) 會以 KC 形式分解,但不是 C 形式。
Ä\uFB03n A\u0308ffin “Äffin”
“Henry IV” “Henry IV” “Henry IV” 此處產生的字串格式為 KC.${REMOVE}$ 相同
“亨利·\u2163” “Henry IV” “Henry IV”
加語 ka +ten 加語 單一日文字符的不同相容性等價會以 KC.${REMOVE}$ 格式形成相同的字串。
ka +ten ka +ten 加語
hw_ka +hw_ten ka +ten 加語
ka +hw_ten ka +ten 加語
hw_ka +十 ka +ten 加語
kaks k i + a ₘ + ks f kaks 韓文字在正常化過程中會保持不變。 在較早的 Unicode 版本中,像 ks f 這樣的字母字符具有與 k f + s f的相容性對應。 這些對應已在 Unicode 2.1.9 中移除,以確保保留韓文音節。

 

注意

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

 

對單一字形使用組合形式

對應至單一字形的許多字元序列沒有組成形式。 即使正規化形式 C,單一視覺字形或邏輯文字元素也可以由多個 Unicode 碼位組成。 例如,在撰寫立陶宛文時使用的數個字元具有雙重變音符號,因為它們只有分解的形式。 例如,具有長音符號和波浪符的小寫 U (“ū̃”, U+016b U+0303,其中第一個字碼點是具有長音符號的小寫 U,而第二個則是結合波浪符號的 U)。

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

使用本地語言支持

安全性考量:國際化功能

正規化字串

正規化字串