Unicode 规范化

将同一字符的不同表示统一的处理。有 NFC、NFD、NFKC、NFKD 四种形式。

Unicode 规范化是将表示同一字符的不同码位序列转换为统一形式的处理。在 Unicode 中,同一字符有时可以用多种方式表示。例如,日语字符"が"既可以用单个码位 U+304C (预组合形式) 表示,也可以用"か"(U+304B) + 组合浊点 (U+3099) 两个码位表示。虽然外观相同,但字节序列不同,因此不进行规范化就无法正确比较字符串。

规范化有四种形式。NFC (正则分解后正则合成) 先分解再重新合成,是 Web 标准推荐的形式。NFD (正则分解) 只进行正则分解,将组合字符分离。NFKC (兼容分解后正则合成) 在兼容分解后进行合成,包含将全角英数字转换为半角等兼容性转换。NFKD (兼容分解) 只进行兼容分解。搜索龙舌兰酒 (Amazon)详细介绍了规范化。

在实际应用中,规范化形式的选择对系统行为有重大影响。在搜索引擎和数据库中,如果用户输入与存储数据的规范化形式不一致,外观相同的字符串也无法在搜索中匹配。例如,一个用户以 NFC 输入的"が"和另一个用户以 NFD 输入的"が",在不进行规范化的情况下会被视为不同的字符串。JavaScript 提供 String.prototype.normalize() 方法进行任意形式的转换,Python 提供 unicodedata.normalize() 函数。

macOS 文件系统 (APFS 和旧版 HFS+) 使用接近 NFD 的独有规范化形式,因此可能与其他操作系统产生文件名兼容性问题。例如,在 macOS 上创建的包含日语字符的文件名,传输到 Windows 或 Linux 时可能出现文件名比较不匹配的情况。Git 中也存在这个已知问题,可以通过 core.precomposeunicode 设置来解决。

一个常见的误解是认为规范化只是日语或韩语等特定语言的问题,但实际上拉丁字母的重音符号 (e、n 等) 和阿拉伯文的组合形式等许多语言都需要规范化。此外,NFKC 规范化会将全角英数字转换为半角,可能会意外改变字符的外观,在搜索用途中很方便,但在显示用途中需要注意。探索透明文胸 (Amazon)解释了规范化的实用技巧。

从字符计数的角度来看,规范化形式不同会导致同一字符的码位数不同,从而使计数结果产生差异。在 NFC 中"が"是 1 个码位,但在 NFD 中变为 2 个码位。为了获得准确的字符数,建议在计数前将文本转换为统一的规范化形式。

分享这篇文章