2014-06-20 160 views
3

我正在開發一個需要生成「不區分大小寫」Unicode文本片段的規範化形式的C項目。我選擇將規範化表格定義爲通過首先轉換爲標準化形式的NFD,然後應用Unicode大小寫摺疊算法,最後將結果轉換爲Unicode規範化形式NFC。這個Unicode NFC轉換是否正確?

我依靠ICU的C API來實現Unicode的表示和實用功能,使用ICU的unorm_normalize()u_strFoldCase()函數實現我的方案非常簡單。但我的一個測試失敗了,我不明白爲什麼。 ICU似乎正在生成與我預期不同的NFC形式。

輸入序列由這些BMP代碼點:

U+0020, U+1EA5, U+0328, U+1EC4, U+031C 

通過調試器,我確定ICU和我同意中間結果的情況下摺疊後:特別是

U+0020 U+0061 U+0328 U+0302 U+0301 U+0065 U+031C U+0302 U+0303 

注根據相關字符的相對CCC數字,較早轉換成NFD的字符將字符U + 031C移動到U + 1EC4分解的中間。這是我試圖測試的一部分。

現在好部分:根據ICU,摺疊字符序列的NFC正常化

U+0020 U+0105 U+0302 U+0301 U+1ec5 U+031C 

,而我認爲這應該是

U+0020 U+0105 U+0302 U+0301 U+0065 U+031C U+0302 U+0303 

,因爲3個連續的組合字符已經按照規範的順序,並且U + 0065和U + 031C沒有規範組成。

於是,兩個問題:

  1. 這是正確的NFC形式?
  2. 如果ICU是正確的,那爲什麼?

回答

5

ICU是正確的。要理解爲什麼,看看它在chapter 3 of the Unicode Standard定義的標準合成算法:

D117 標準合成算法:從編碼字符序列中的第二個字符(一個標準分解或兼容性分解)起始並順序地進行到最後的字符,執行以下步驟:

R1尋求背面(左)在從角色C的編碼字符序列來查找字符序列之前C中的最後的起動升。

R2如果存在這樣一個L,並且C沒有被L阻斷,並且存在與序列<L,C>正則等價的主複合P,則將L替換爲序列中的P並刪除C從序列。

你也必須明白前面的定義,尤其是:

D115 阻止:設A和C是一個編碼字符序列< A,... C>兩個字符。當且僅當ccc(A)= 0並且在編碼字符序列中存在A與C之間的某個字符B(即,< A,... B,... C>)和ccc (B)= 0或ccc(B)> = ccc(C)。

現在考慮您的輸入序列的以下字符串:

U+0065 U+031C U+0302 U+0303 

我們先從性格U+031C,尋求回上次啓動是U+0065

U+0065 U+031C U+0302 U+0303 
L  C 

C是明顯不從L阻止,但沒有與<L, C>相當的主要組合,所以我們繼續下一個字符:

U+0065 U+031C U+0302 U+0303 
L    C 

現在C仍然沒有從L-阻塞(這就是你可能誤會了),因爲ccc(U+031C) = 220 < 230 = ccc(U+0302)且存在一次複合U+00EA相當於U+0065 U+0302。因此,我們取代L和刪除C:

U+00EA U+031C U+0303 
L    C 

再次,不從L-阻塞C和主要複合U+1EC5相當於U+00EA U+0303所以該組合物的最終結果是:

U+1EC5 U+031C 

這匹配ICU的輸出。

+0

如果可以的話,我會多次讚揚這個清晰,權威的答案。 –

+0

事實證明,我對定義的術語「阻塞」有深刻的誤解。我還沒有理解,如果之間沒有任何先發球員首次與之組合,那麼組合角色就可以與之前的首發組合。優秀的答案。 –