规范化字符串会产生与规范化单个字素簇相同的结果吗?

Will normalizing a string give the same result as normalizing the individual grapheme clusters?

对字符串执行 Unicode 规范化(假设没有孤立的组合字符)的结果是否与将字符串拆分为字素簇、分别规范化每个簇然后连接规范化的字素簇的结果相同? (如果是这样,这是否仅适用于规范化形式的子集?)

问这个主要是出于对 Unicode 工作原理的兴趣,并弄清楚可能存在哪些潜在的边缘情况,而不是作为具体应用程序的一部分。

不,这通常不是真的。 Unicode 标准警告不要假设连接规范化字符串会产生另一个规范化字符串。来自 UAX #15:

In using normalization functions, it is important to realize that none of the Normalization Forms are closed under string concatenation. That is, even if two strings X and Y are normalized, their string concatenation X+Y is not guaranteed to be normalized.

Unicode 文本分割算法的许多方面都是可定制的;该标准主要只提供在大多数情况下有用的默认值,但在出于特定目的需要时可以覆盖。因此,无法保证两个 Unicode-compliant 应用程序甚至会就字素边界所在的位置达成一致。一个具体的例子是 legacy grapheme clustersextended grapheme clusters.

之间的区别

在前者中,具有 Grapheme_Cluster_Break 属性 值 Spacing_MarkPrepend 的字符不充当字素扩展器,而在后者中它们是。从 Unicode 12.1 开始,有 twelve such characters with a non-zero canonical combining class。如果您使用遗留字形簇定义,这些字符会破坏您的方法,例如按以下顺序:

<U+1D158, U+1D16D, U+1D166>

也就是

  • 音乐符号符头黑色 (ccc=0)
  • 音乐符号组合增强点 (ccc=226)
  • 结合 SPRECHGESANG STEM 的音乐符号 (ccc=216)

因为组合增强点和组合sprechgesang词干都是Spacing_Mark,这个序列实际上被分成三个遗留字素簇,每个只有一个字符的长度,因此自动归一化。然而,由于它们的 CCC 值,整个字符串的真正规范化会交换点和词干的位置。

如果我们忽略调整算法的可能性,只关注严格按照标准定义的扩展字素簇,那么单独规范化每个字素簇应该产生与据我所知立即规范化整个字符串,但没有正式保证标准的未来修订不会改变这一点。