2014-06-20 111 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

事实证明,我对定义的术语“阻塞”有深刻的误解。我还没有理解,如果之间没有任何先发球员首次与之组合,那么组合角色就可以与之前的首发组合。优秀的答案。 –