3
#!/usr/local/bin/perl
use warnings;
use 5.014;
use Unicode::Normalize qw(NFD NFC compose);


my $string1 = "\x{f5}";

my $NFD_string1 = NFD( $string1 ); 
# PV = 0x831150 "o\314\203"\0 [UTF8 "o\x{303}"] *

my $composed_NFD_string1 = compose( $NFD_string1 ); 
#  PV = 0x77bc40 "\303\265"\0 [UTF8 "\x{f5}"] *

my $NFC_string1 = NFC( $string1 );
#  PV = 0x836e30 "\303\265"\0 [UTF8 "\x{f5}"] *


my $string2 = "o\x{303}";

my $NFD_string2 = NFD( $string2 );
#  PV = 0x780da0 "o\314\203"\0 [UTF8 "o\x{303}"] *

my $composed_NFD_string2 = compose( $NFD_string2 ); 
#  PV = 0x782dc0 "\303\265"\0 [UTF8 "\x{f5}"] *  

my $NFC_string2 = NFC( $string2 );
#  PV = 0x7acba0 "\303\265"\0 [UTF8 "\x{f5}"] * 

# * from Devel::Peek::Dump output


say 'OK' if $NFD_string1 eq $NFD_string2;
say 'OK' if $NFC_string1 eq $NFC_string2;

输出:

好的
好的

在尝试了这个之后,我问我:有没有理由使用 theNormalization Form D而不是Normalization Form C

4

1 回答 1

3

不是所有的东西都有复合形式,NFC实际上是先做一个NFD。NFD 的一部分是将延续字符按顺序排列在起始字符之后,以便您可以比较两个字素簇(起始字符的花哨名称及其延续字符)以查看它们是否相同。对于您在此示例中所做的事情,您应该得到相同的答案,但 NFC 实际上做了更多的工作。

有些东西没有特殊的 NFC 版本有几个原因。其中许多来自历史字符集。é 的组合版本是为了让拉丁 1 人开心。还有 e 和 ´ 版本旨在让您自己构建字形。有很多方法可以做到这一点,而不仅仅是口音和变音符号。字素簇可以有几个这样的连续字符,当你自己构建它们时,你可以把它们按你喜欢的任何顺序排列(不管出于什么原因)。但是,他们已经分配了权重。NFD 将按它们的权重对它们重新排序,因此您可以比较两个字素簇,尽管您使用的顺序。

正如 daxim 在评论中所说,这一切都在Unicode Technical Report 15中。您将希望查看图表并阅读以下内容:

一旦一个字符串被完全分解,它包含的任何组合标记序列都会被放入一个明确定义的顺序中。这种组合标记的重新排列是根据称为规范排序算法的 Unicode 规范化算法的子部分完成的。该算法根据其 Canonical_Combining_Class (ccc) 属性的值对组合标记序列进行排序,其值也在 UnicodeData.txt 中定义。大多数字符(包括所有非组合标记)的 Canonical_Combining_Class 值为零,并且不受规范排序算法的影响。这样的字符由一个特殊的术语,starter 来指代。只有具有非零 Canonical_Combining_Class 属性值的组合标记子集才可能受到规范排序算法的重新排序。

有些东西明确使用 NFD 来存储数据,例如 HFS+ 文件系统。在许多情况下,这并不重要,因为您的编程语言可能绑定到将文件名字符串转换为正确形式的库函数。

今天晚些时候,我将上传Unicode::Support,它演示了其中的许多内容。

而且,今天晚些时候,汤姆会来给我们上课。:)

于 2011-07-21T19:33:00.653 回答