标准化的 UTF-8到底是什么?

重症监护室项目(现在也有一个 PHP 库)包含帮助规范化 UTF-8字符串所需的类,以便在搜索时更容易比较值。

然而,我正在尝试找出应用程序的 这意味着什么。例如,在哪些情况下,我想要“规范等价”而不是“兼容等价”,或者相反?

21995 次浏览

标准格式(Unicode 格式,不是数据库格式)主要(专门?)处理有发音符号的字符。Unicode 提供了一些带有“内置”发音符号的字符,如 U + 00 C0、“带有坟墓的拉丁大写字母 A”。同样的字符可以从“拉丁大写字母 A”(U + 0041)和“结合严重口音”(U + 0300)创建。这意味着即使这两个序列生成相同的结果字符,逐字节比较也会显示它们完全不同。

正常化是处理这个问题的一种尝试。规范化确保(或者至少尝试)所有字符都以相同的方式编码——或者在需要的地方使用单独的组合附加符号,或者在可能的情况下使用单个编码点。从比较的角度来看,选择哪个并不重要——几乎任何规范化字符串都可以与另一个规范化字符串正确地进行比较。

在这种情况下,“兼容性”意味着与假定一个代码点等于一个字符的代码的兼容性。如果您有这样的代码,您可能希望使用兼容性标准格式。虽然我从来没有看到它直接说明,正常形式的名称意味着,统一码联盟认为最好使用单独的组合发音符号。这需要更多的智能来计算字符串中的实际字符数(以及智能地断开字符串之类的事情) ,但是它更加通用。

如果您正在充分利用 ICU,那么您可能希望使用规范标准格式。如果您试图自己编写代码,(例如)假设一个代码点等于一个字符,那么您可能需要兼容性标准格式,以便尽可能多地实现这一点。

如果两个 unicode 字符串在规范上是等价的,那么这两个字符串实际上是相同的,只是使用了不同的 unicode 序列。例如,可以使用字符 Ä 或 A 和 something 的组合来表示 Ä。

如果字符串只是兼容等价的,那么字符串不一定相同,但是在某些上下文中它们可能是相同的。例如 ff 可以被认为与 ff 相同。

因此,如果要比较字符串,应该使用规范等价,因为兼容等价不是真正的等价。

但是如果您想对一组字符串进行排序,那么使用兼容性等价可能是有意义的,因为这些字符串几乎是相同的。

规范等价或兼容等价是否与您更相关取决于您的应用程序。ASCII 思考字符串比较的方式大致映射到规范等价,但 Unicode 代表了许多语言。我认为,假设 Unicode 编码所有语言的方式允许您像对待西欧 ASCII 一样对待它们,这种假设是不安全的。

图1和图2 为这两种类型的等价提供了很好的例子。在兼容性等价条件下,子脚本和上标形式的相同数字看起来是相等的。但我不确定这能否解决草书阿拉伯文形式或旋转字符的同样问题。

Unicode 文本处理的残酷现实是,必须深入思考应用程序的文本处理需求,然后尽可能利用现有工具解决这些需求。这并没有直接回答你的问题,但是一个更详细的答案需要你希望支持的每种语言的语言专家。

有些字符,例如带有重音的字母(比如说 é)可以用两种方式表示——一个单一的代码点 U+00E9或者后面跟着一个组合重音符号 U+0065 U+0301的普通字母。普通的规范化将选择其中的一个来总是表示它(NFC 的单个代码点,NFD 的组合形式)。

对于可以由多个基本字符序列和组合标记表示的字符(比如,“ s,点以下,点以上”与在上面加点然后在下面加点,或者使用已经有一个点的基本字符) ,NFD 也会选择其中一个(下面先去,因为它发生了)

兼容性分解包括许多字符,这些字符“实际上不应该”是字符,而是因为它们在遗留编码中使用。普通的标准化不会统一这些(为了保持往返完整性——这对于组合表单来说不是问题,因为没有遗留编码(除了少数越南编码)同时使用这两种编码) ,但是兼容性标准化会。想象一下出现在一些东亚编码中的“ kg”公斤符号(或者半宽/全宽片假名和字母表) ,或者 MacRoman 中的“ fi”连字符。

有关详细信息,请参阅 http://unicode.org/reports/tr15/

这其实很简单。UTF-8实际上对同一个“字符”有几种不同的表示。(我使用引号中的字符,因为它们在字节方面是不同的,但实际上它们是相同的)。链接文档中给出了一个例子。

字符“ Ç”可以表示为字节序列0xc387。但是它也可以用 C(0x43)和字节序列0xcca7来表示。因此可以说0xc387和0x43cca7是同一个字符。原因是0xcca7是一个组合标记; 也就是说,它接受前面的字符(这里是 C) ,并对其进行修改。

现在,至于规范等价和兼容等价之间的区别,我们需要从一般角度来看字符。

有两种类型的字符,一种是通过 价值表达意思,另一种是采用另一个字符并对其进行修改。9是一个有意义的字符。超级脚本9接受这个意思,并通过表示来改变它。因此,按照规范,它们有不同的含义,但它们仍然代表基本字符。

规范等效是指字节序列呈现具有相同含义的相同字符。兼容性等价是指当字节序列呈现具有相同基本含义的不同字符时(即使它可能被更改)。9和9是兼容性等价的,因为它们都表示“9”,但是由于它们没有相同的表示形式,所以在规范上不是等价的。

关于 Unicode 规范化你永远不想知道的一切

规范标准化

Unicode 包括多种对某些字符进行编码的方法,最明显的是重音字符。规范标准化将代码点更改为规范编码形式。生成的代码点应该与原始代码点相同,除非在字体或呈现引擎中出现任何错误。

何时使用

因为结果看起来是相同的,所以在存储或显示字符串之前对其应用规范化总是安全的,只要您能够容忍结果与输入不是一位一位的相同。

规范标准化有两种形式: NFD 和 NFC。两者是等价的,因为人们可以在这两种形式之间转换而不会有损失。在 NFC 下比较两个字符串将总是得到与在 NFC 下比较它们相同的结果。

NFD

NFD 将角色完全展开。这是可以计算的更快的规范化形式,但是结果会产生更多的代码点(即使用更多的空间)。

如果您只想比较两个尚未规范化的字符串,则这是首选的规范化形式,除非您知道需要兼容性规范化。

NFC

NFC 在运行 NFD 算法后尽可能重新组合代码点。这会花费更长的时间,但结果是字符串更短。

兼容性标准化

Unicode 还包括许多实际上不属于、但在遗留字符集中使用的字符。Unicode 添加了这些字符集,以允许将这些字符集中的文本作为 Unicode 处理,然后在不丢失的情况下将其转换回来。

兼容规范化将这些字符转换为相应的“实”字符序列,并执行规范规范化。兼容性标准化的结果可能与原始文件不一致。

包含格式设置信息的字符将替换为不包含格式设置信息的字符。例如,字符 被转换为 9。其他的则不涉及格式差异。例如,罗马数字字符 被转换为正则字母 IX

显然,一旦执行了这种转换,就不再可能无损地转换回原始字符集。

何时使用

统一码联盟建议将兼容性标准化想象成 ToUpperCase转换。它在某些情况下可能是有用的,但是你不应该随意地应用它。

一个优秀的用例将是搜索引擎,因为您可能希望搜索 9以匹配

您可能不应该做的一件事是显示向用户应用兼容性规范化的结果。

NFKC/NFKD

兼容性标准化表现为 NFKD 和 NFKC 两种形式,它们之间的关系与 NFD 和 C 之间的关系相同。

NFKC 中的任何字符串本质上也是 NFC 中的字符串,NFKD 和 NFD 也是如此。比如 NFKD(x)=NFD(NFKC(x))NFKC(x)=NFC(NFKD(x))等等。

结论

如果有疑问,就使用规范标准化。根据适用的空间/速度权衡,或者根据您正在进行交互操作的东西的需要,选择 NFC 或 NFD。

比较字符串的问题: 对于大多数应用程序来说,内容等价的两个字符串可能包含不同的字符序列。

参见 Unicode 的规范等效: 如果比较算法很简单(或者必须很快) ,则不执行 统一码等价性。例如,在 XML 规范比较中会出现此问题,请参阅 http://www.w3.org/TR/xml-c14n

为了避免这个问题... 使用什么标准? “扩展的 UTF8”还是“紧凑的 UTF8”?
用“ ç”还是“ c + something”?

W3C 及其他(例如。文件名)建议使用“组成为规范”(请记住“最紧凑”短字符串的 C) ... ... 因此,

标准是 C! 使用 NFC有疑问

对于互操作性和 “约定优于配置”的选择,建议使用 NFC“规范化”外部字符串。例如,要存储规范化 XML,请将其存储在“ FORM _ C”中。W3C 的 < em > CSV on Web 工作组 也建议使用 NFC(第7.2节)。

“ FORM _ C”是大多数库中的 预设表格


术语“ 构图 form”(FORM_C)既用于表示“字符串采用 C 规范形式”(NFC 转换的结果) ,也用于表示使用了转换算法... ... 参见 http://www.macchiato.com/unicode/nfc-faq

(...)下列每个序列(前两个是单字符序列)表示相同的字符:

  1. U + 00 C5(Å)拉丁文大写字母 A 上面带环
  2. U + 212B (Å) ANGSTROM 符号
  3. U + 0041(A)拉丁大写字母 A + U + 030A ()上面的组合环

这些序列被称为规范等价序列。这些表单中的第一种称为 NFC-表示规范化表单 C,其中 C 表示 构图。 (...)将字符串 S 转换为 NFC 形式的函数可以缩写为 toNFC(S),而测试 S 是否处于 NFC 中的函数可以缩写为 isNFC(S)


注意: 要测试小字符串(纯 UTF-8或 XML 实体引用)的规范化,可以使用 此测试/规范化在线转换器