# 报表客户名看起来一样却匹配不上：用 unicodedata 统一 Unicode 形态并输出异常字符清单

## 文档明确的机制

Python 标准库 `unicodedata` 提供对 Unicode Character Database 的访问。给定文档页对应 Python 3.15.2，数据库编译自 UCD 17.0.0；它能查询字符名称、类别、数值属性，也能执行 Unicode 规范化。

报表里的客户名、SKU、账号在 CSV 或 Excel 导出后“肉眼相同”，代码比较却可能不相等。文档明确说明：同一个字符可能有多种表达方式，例如 `U+00C7`（带下加符的拉丁大写字母 C）也可表示为 `U+0043` 加 `U+0327`（组合下加符）。即使字符串已经规范化，若一个字符串含组合字符、另一个不含，也可能不相等。

`unicodedata.normalize(form, unistr)` 可返回指定正规形式，合法的 `form` 只有 `NFC`、`NFD`、`NFKC`、`NFKD`。其中 NFD 是规范分解，把字符转为分解形式；NFC 先规范分解，再重新组合预组合字符。NFKD 执行兼容分解，把兼容字符替换为等价物；NFKC 先兼容分解，再做规范组合。`is_normalized(form, unistr)` 可检查字符串是否处于指定形式，同样只接受这四种形式。

这四种形式不能混为“安全展示转换”。文档用罗马数字举例：`U+2160`（ROMAN NUMERAL ONE）因兼容既有字符集而存在，NFKD/NFKC 会按兼容等价处理。换言之，NFKC/NFKD 可能把兼容字符转换成另一串文本。团队若把转换结果直接覆盖客户原始名称，就可能改变原始语义或展示值。

异常清单可以直接使用文档列出的字符属性函数：`name(chr)` 返回字符名称；`category(chr)` 返回两字母通用类别；`decomposition(chr)` 返回分解映射；`combining(chr)` 返回规范组合类；`east_asian_width(chr)` 返回东亚宽度；`decimal(chr)`、`digit(chr)`、`numeric(chr)` 分别取得文档定义的十进制值、数字值和数值。文档示例显示，`numeric('½')` 返回 `0.5`，`digit('SUPERSCRIPT NINE')` 返回 `9`，但 `decimal('SUPERSCRIPT NINE', -1)` 返回默认值 `-1`。因此，“看起来像数字”的字符不应被统一假定具有同一类数值属性。

## 团队自行约定的接手建议（非 Python 文档承诺）

以下是面向小团队入站处理 CSV/Excel 文本列的约定，不是 `unicodedata` 文档提供的完整流程。

**团队建议：先检测，再按白名单转换，并保留原值。**

1. **保留原始字段**：新增“原始客户名”“原始 SKU”“原始账号”等列，不把规范化结果回写成用户提交值。
2. **先做形态检测**：对同一列分别调用 `is_normalized("NFC", s)`、`is_normalized("NFD", s)` 等检查，记录当前是否已处于目标形式。
3. **生成匹配键时限定形式**：可先约定团队使用 NFC 或 NFD 作为匹配键；涉及兼容字符时，NFKC/NFKD 只能进入白名单评估，不应默认批量执行。
4. **输出逐字符清单**：对仍未匹配的记录，按 Python 字符串位置列出码位、`name`、`category`，必要时补充 `combining`、`decomposition`、`east_asian_width`。
5. **相似数字单独标注**：对疑似数字字符分别尝试 `decimal`、`digit`、`numeric`，把无对应值或属性不同的情况写入异常，而不是自动改账。
6. **白名单转换**：只有团队确认某类兼容字符在本业务中可互换，才把对应 NFKC/NFKD 结果用于匹配键；每次转换都保留转换前后差异。
7. **emoji 与字形簇只做分段线索**：Python 3.15 文档中的 `iter_graphemes(unistr)` 按扩展字形簇规则迭代，可辅助定位用户可见字形；它不是业务分词规则，也不能证明两个字形簇在客户名或 SKU 中可互换。

交接产物建议包含三部分：规范化后的匹配字段、规范化前后仍不一致的记录、异常字符清单。清单至少保存字段名、行号、字符串位置、码位、字符名称和类别；若使用了数值属性，再记录具体函数和返回值。这样接手人可以复核“为什么没匹配上”，而不是只看到一个去重后的结果。

## 边界与总结

`unicodedata` 解决的是 Unicode 字符属性与正规形式问题。它不会替团队判断别名、错别字、字号差异、业务主体合并规则，也不会证明 NFKC/NFKD 后的文本仍应原样展示。尤其 NFKC/NFKD 基于兼容等价，可能改变字符序列；是否允许把全角/半角、兼容数字、罗马数字等视作同一业务键，必须由团队按字段和白名单决定。

因此，稳妥做法是：把文档明确给出的 NFC/NFD/NFKC/NFKD、`is_normalized`、`name`、`category`、数值属性和 `iter_graphemes` 用作检测与证据工具；把“先检测、白名单转换、保留原值、输出异常”限定为团队自己的接手约定。这样既能解释“看起来一样却匹配不上”的具体字符原因，也不会把可能改变语义的规范化结果误当作用户原始值。

## 相关工具

[AI 工作流 ROI 诊断器](/demos/ai-workflow-roi-diagnostic/index.html) · 查看工具的输入要求、输出说明与适用范围。


来源：[报表客户名看起来一样却匹配不上：用 unicodedata 统一 Unicode 形态并输出异常字符清单](https://docs.python.org/3/library/unicodedata.html)
