这种Unicode NFC转换正确吗?

这种Unicode NFC转换正确吗?,unicode,normalization,icu,unicode-normalization,Unicode,Normalization,Icu,Unicode Normalization,我正在从事一个C项目,该项目需要生成Unicode文本片段的“不区分大小写”规范化形式。我选择将规范化表单定义为:首先转换为规范化表单NFD,然后应用Unicode大小写折叠算法,最后将结果转换为Unicode规范化表单NFC 我依靠ICU的C API实现其Unicode表示和实用函数,使用ICU的unorm\u normalize()和u strFoldCase()函数实现我的方案非常简单。但我有一次考试不及格,我不明白为什么。ICU似乎产生了一种不同于我预期的NFC形式 输入序列由以下BMP

我正在从事一个C项目,该项目需要生成Unicode文本片段的“不区分大小写”规范化形式。我选择将规范化表单定义为:首先转换为规范化表单NFD,然后应用Unicode大小写折叠算法,最后将结果转换为Unicode规范化表单NFC

我依靠ICU的C API实现其Unicode表示和实用函数,使用ICU的
unorm\u 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
特别要注意的是,早期的NFD转换将字符U+031C移动到了U+1EC4分解的中间,这是根据所涉及字符的相对CCC编号而定的。这是我想测试的一部分

好的方面是:根据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
因为这三个尾随组合字符已经按规范顺序排列,并且没有U+0065和U+031C的规范组合

因此,有两个问题:

  • 哪一种是正确的NFC形式
  • 如果ICU是正确的,为什么

  • ICU是正确的。要了解原因,请查看规范合成算法,该算法定义于:

    D117规范组合算法:从编码字符序列(规范分解或兼容性分解)中的第二个字符开始,依次进行到最后一个字符,执行以下步骤:

    R1在编码字符序列中从字符C向后搜索(左),以查找字符序列中C之前的最后一个起始字符L

    R2如果存在这样一个L,并且C没有被L阻止,并且存在一个与序列正则等价的主复合p,那么在序列中用p替换L,并从序列中删除C

    您还必须理解上述定义,尤其是:

    D115阻塞:设A和C为编码字符序列中的两个字符。当且仅当ccc(A)=0且编码字符序列中A和C之间存在某些字符B,即ccc(B)=0或ccc(B)>=ccc(C)时,C从A被阻止

    现在考虑以下输入序列的子串:

    U+0065 U+031C U+0302 U+0303
    
    我们从字符
    U+031C
    开始,然后返回到最后一个起始字符
    U+0065

    U+0065 U+031C U+0302 U+0303
    L      C
    
    C显然没有被L阻止,但没有与
    等价的主复合符,因此我们继续下一个字符:

    U+0065 U+031C U+0302 U+0303
    L             C
    
    现在C仍然没有从L中被阻止(这可能是您误解的),因为
    ccc(U+031C)=220<230=ccc(U+0302)
    ,并且存在一个与
    U+0065U+0302
    等价的主复合
    U+00EA
    。因此,我们替换L并删除C:

    U+00EA U+031C U+0303
    L             C
    
    同样,C不会从L中被阻止,并且主要组合
    U+1EC5
    相当于
    U+00EA U+0303
    ,因此合成的最终结果是:

    U+1EC5 U+031C
    

    这与ICU的结果相符。

    如果可能的话,我会多次对这个明确、权威的答案进行投票。结果证明,我对定义为“阻塞”的术语有着深刻的误解。我不明白,如果两个角色之间的任何一个非起始者没有首先与前一个起始者组合,那么组合角色就可以与前一个起始者组合。回答得很好。