首页/开发/正则与编码速查/NFD 分解归一化的影响

NFD 分解归一化的影响

NFD 是分解式归一化:把预组合字符拆成基字符加组合标记,便于按基字符检索与处理,但会改变码点数量与字节长度,且与 NFC 形式的字符串不相等。

正则与编码速查开发更新于 2026-10-17
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌​​‌​‌‌‌‌​‌‌‌​​‌​​‌‌​​‌​‌​‌‌​​‌‌‌​‌‌​​‌​‌​‌‌‌‌​​​​​‌​‌‌‌‌​‌‌‌​‌​‌​‌‌​‌‌‌​​‌‌​‌​​‌​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​​‌​​​‌‌​​‌​‌​​‌​‌‌​‌​‌‌​‌‌‌​​‌‌​‌‌‌‌​‌‌‌​​‌​​‌‌​‌‌​‌​‌‌​​​​‌​‌‌​‌‌​​​‌‌​‌​​‌​‌‌‌‌​‌​​‌‌​​​​‌​‌‌‌​‌​​​‌‌​‌​​‌​‌‌​‌‌‌‌​‌‌​‌‌‌​​​‌​‌‌​‌​‌‌​‌‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌​‌‌‌​​‌‌​‌​​​​‌‌‌​‌​​​‌‌​‌‌​‌​‌‌​‌‌​​

NFD 做什么

NFD(Normalization Form Canonical Decomposition)按规范分解规则把字符拆开:预组合的重音字母变成基字母加组合标记,韩文音节拆成字母序列。它不重新组合,因此得到的是「尽量分解」的形式。用途集中在需要按键位或基础字符做匹配的场景,例如忽略重音的搜索、按基字母建索引、字体与渲染管线处理组合标记。代价是码点数变多、字节变长,且与 NFC 内容不相等。

基本信息

定义规范等价下的分解形式(Canonical Decomposition)
典型效果预组合字符拆成基字符加组合标记
码点变化通常变多,长度与字节数增加
是否改变语义规范等价,语义不变
典型用途忽略重音的检索、基字符索引、渲染处理
注意点与 NFC 结果不相等,混用会导致比较失败

典型使用场景

  • 忽略重音的搜索:把两侧文本都分解并去掉组合标记后比较
  • 排序与分组:按基字符归组,把 é 与 e 视为同一组
  • 字体与排版:文本渲染引擎常按分解形式处理标记定位
  • 数据清洗:把形态不统一的输入拆开再统一重组,便于后续处理
  • 字符统计:区分基字符与组合标记,统计实际内容构成

分解与去标记示例

分解与去标记示例
python -c "import unicodedata as u; s=u.normalize('NFD','\u00e9'); print(len(s), [hex(ord(c)) for c in s])"   # 2 个码点:e + 组合尖音符
python -c "import unicodedata as u; print(u.normalize('NFD','\u00e9') == '\u00e9')"                       # False:形式不同
python -c "import unicodedata as u; s=u.normalize('NFD','caf\u00e9'); print(''.join(c for c in s if u.category(c)!='Mn'))"  # 去掉组合标记得到 cafe
# 常见检索流程:两侧都 NFD 再去标记 → 比较;展示时用 NFC
python -c "import unicodedata as u; print(u.normalize('NFC', u.normalize('NFD','caf\u00e9')))"            # 可逆回到 NFC

NFC 与 NFD 对比

维度NFCNFD
方向合成分解
重音字母单码点基字符加组合标记
码点数量通常较少通常较多
字节长度通常较短通常较长
推荐用途存储、交换、比较检索、索引、渲染处理
两者相等性互相不相等互相不相等
NFD 不等于「去掉重音」:它只是把字符拆开,组合标记仍在字符串里。要得到无重音文本,需要在分解后按通用类别过滤掉标记字符,这一步属于业务逻辑,不同语言的实现方式不同。
归一化可逆性有前提:从 NFC 到 NFD 再回到 NFC 通常能还原,但经过兼容归一化(NFKC/NFKD)或自定义过滤后就不再可逆,涉及存储与检索时要把两种形式分别处理。
排序与比较的正确做法是使用语言相关的排序算法(collation),而不是自己用 NFD 拼凑:Unicode 提供了排序算法标准,能处理重音、大小写、区域差异等规则,自研规则很难覆盖全语言。

易错点

  • 把 NFD 内容当作存储形式:长度与字节增加,且与外部系统的 NFC 内容比较失败 → 存储与交换用 NFC,检索内部再按需分解
  • 以为 NFD 会去掉重音:组合标记仍在文本中,检索结果与预期不符 → 分解后再按类别过滤标记
  • 混用两种归一化形式建索引与查询:同义内容匹配不到,出现诡异的漏召回 → 索引与查询使用同一形式
  • 忽略分解后的长度变化:字段长度校验在两种形式下结果不同 → 归一化与长度校验按固定顺序执行
  • 用归一化替代排序算法:多语言排序结果不符合语言习惯 → 使用语言相关 collation

数据来源与参考

  • Unicode 官方:Normalization Forms(UAX #15)
  • Unicode 官方:规范等价与兼容等价的定义
  • Python 官方文档:unicodedata.normalize 与组合标记处理

整理校对:其其网ICT文档中心 · 本页地址:docs.qiqicto.com/regex/unicode-normalization-nfd.html

​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌​​‌​‌‌‌‌​‌‌‌​​‌​​‌‌​​‌​‌​‌‌​​‌‌‌​‌‌​​‌​‌​‌‌‌‌​​​​​‌​‌‌‌‌​‌‌‌​‌​‌​‌‌​‌‌‌​​‌‌​‌​​‌​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​​‌​​​‌‌​​‌​‌​​‌​‌‌​‌​‌‌​‌‌‌​​‌‌​‌‌‌‌​‌‌‌​​‌​​‌‌​‌‌​‌​‌‌​​​​‌​‌‌​‌‌​​​‌‌​‌​​‌​‌‌‌‌​‌​​‌‌​​​​‌​‌‌‌​‌​​​‌‌​‌​​‌​‌‌​‌‌‌‌​‌‌​‌‌‌​​​‌​‌‌​‌​‌‌​‌‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌​‌‌‌​​‌‌​‌​​​​‌‌‌​‌​​​‌‌​‌‌​‌​‌‌​‌‌​​