什么是规范化的 UTF-8?你从来不想知道的关于Unicode规范化的所有信息
ICU 项目(现在也有 PHP 库)包含帮助规范化 UTF-8 字符串所需的类,以便在搜索时更轻松地比较值。
但是,我试图弄清楚这对应用程序意味着什么。例如,在哪些情况下,我想要“规范等价”而不是“兼容性等价”,反之亦然?
ICU 项目(现在也有 PHP 库)包含帮助规范化 UTF-8 字符串所需的类,以便在搜索时更轻松地比较值。
但是,我试图弄清楚这对应用程序意味着什么。例如,在哪些情况下,我想要“规范等价”而不是“兼容性等价”,反之亦然?
Unicode 包含多种编码某些字符的方法,最明显的是重音字符。规范规范化将代码点更改为规范编码形式。生成的代码点应与原始代码点相同,除非字体或呈现引擎中存在任何错误。
由于结果看起来相同,因此在存储或显示字符串之前对字符串应用规范化始终是安全的,只要您可以容忍结果不是与输入相同的位对位。
规范规范化有两种形式:NFD 和 NFC。从某种意义上说,两者是等价的,人们可以在这两种形式之间转换而不会丢失。在NFC下比较两个字符串将始终给出与在NFD下比较它们相同的结果。
NFD已将字符完全展开。这是计算速度更快的规范化形式,但结果是更多的码位(即使用更多的空间)。
如果您只想比较两个尚未规范化的字符串,这是首选的规范化形式,除非您知道需要兼容性规范化。
NFC 在运行 NFD 算法后尽可能重新组合代码点。这需要更长的时间,但会导致字符串更短。
Unicode 还包括许多实际上不属于的字符,但这些字符在旧字符集中使用。Unicode 添加了这些字符,以允许将这些字符集中的文本作为 Unicode 进行处理,然后转换回来而不会丢失。
兼容性规范化将这些字符转换为相应的“真实”字符序列,并执行规范规范化。兼容性规范化的结果可能看起来与原始结果不同。
包含格式设置信息的字符将替换为不包含格式设置信息的字符。例如,字符转换为 .其他不涉及格式差异。例如,罗马数字字符转换为常规字母。⁹
9
Ⅸ
IX
显然,一旦执行了此转换,就不再可能无损地转换回原始字符集。
Unicode 联盟建议将兼容性规范化视为转换。在某些情况下,它可能是有用的东西,但你不应该随意应用它。ToUpperCase
一个优秀的用例是搜索引擎,因为您可能希望搜索与 匹配 。9
⁹
您可能不应该做的一件事是显示对用户应用兼容性规范化的结果。
兼容性规范化形式有两种形式 NFKD 和 NFKC。它们与NFD和C之间的关系相同。
NFKC 中的任何字符串本质上也存在于 NFC 中,NFKD 和 NFD 也是如此。因此,和 等。NFKD(x)=NFD(NFKC(x))
NFKC(x)=NFC(NFKD(x))
如果有疑问,请使用规范规范化。根据适用的空间/速度权衡,或根据您正在与之交互的事物所需的内容,选择 NFC 或 NFD。
某些字符,例如带有重音符号的字母(例如),可以用两种方式表示 - 单个码位或普通字母后跟组合重音符号。普通规范化将选择其中之一来始终表示它(NFC的单个码位,NFD的组合形式)。é
U+00E9
U+0065 U+0301
对于可以由多个基本字符序列和组合标记表示的字符(例如,“s,dot below,dot above”与将点放在上面然后点下面或使用已经具有其中一个点的基本字符),NFD还将选择其中一个(下面先去,因为它发生时)
兼容性分解包括许多字符,这些字符“不应该真正”是字符,而是因为它们在传统编码中使用。普通的规范化不会统一这些(以保持往返完整性 - 这对于组合形式来说不是问题,因为没有遗留编码(除了少数越南编码)同时使用),但兼容性规范化会。想想一些东亚编码中出现的“kg”千克符号(或半角/全角片假名和字母),或者MacRoman中的“fi”连字。