返回

Unicode 规范化

文本处理

正在载入

正在加载工具

工具代码会在打开时按需载入,请稍候。

本工具的全部运算都发生在你的浏览器中,输入内容不会发送到任何服务器。

关于这个工具

看起来相同的文字可能由不同的 Unicode 序列组成。工具保留原文,在浏览器本地同时比较 NFC、NFD、NFKC 和 NFKD,并提供精确转义预览、码点列表、UTF-16 单元数及 UTF-8 字节数。规范等价的规范化会组合或分解规范等价的序列;兼容规范化还会合并部分连字、全角字符和圈号数字等区别,可能丢失应用所需的含义或排版信息。请先检查变化,再选择适合目标系统的输出。

常见用途

  • 排查从不同来源复制的带重音姓名看似相同、精确字符串比较却不匹配的原因。
  • 比较预组合韩文音节与分解后的组合字母,观察码点数和 UTF-8 字节数的变化。
  • 在确定导入或搜索流程的规范化规则前,审阅 NFKC、NFKD 对兼容字符产生的额外转换。

使用方法

  1. 1.粘贴实际文字或打开一个严格 UTF-8 解码的本地文本文件,然后开始比较。原文和四种形式均来自同一份完整输入。\u0301 这样的拼写只是普通 ASCII,除非输入实际组合字符;下方示例使用 ASCII JSON 只是为了准确展示测试数据。
  2. 2.对照已变化/未变化状态、转义预览、码点预览及 UTF-16/UTF-8 计数。每份文本预览最多覆盖 2,000 个源 UTF-16 单元及 12,000 个渲染后的 ASCII 字符,U+ 序列最多显示 80 个码点。截短会明确标记,不会缩短保存的结果或完整报告。根据接收系统的规则选择形式,并检查语义。
  3. 3.明确审阅所选结果后,复制或下载完整文本。ASCII 安全 JSON 报告保留原文和全部四种形式。编辑输入会使旧比较及审阅状态失效;不成对 UTF-16 代理项会阻止原始文本导出,但仍可在转义 JSON 中无损保留。

精确、可复现的规范化示例

组合带重音序列

input (ASCII JSON): "e\u0301"
{"original":{"text":"e\u0301","codePoints":2,"utf16Units":2,"utf8Bytes":3},"NFC":{"text":"\u00E9","codePoints":1,"utf16Units":1,"utf8Bytes":2},"NFD":{"text":"e\u0301","codePoints":2,"utf16Units":2,"utf8Bytes":3},"NFKC":{"text":"\u00E9","codePoints":1,"utf16Units":1,"utf8Bytes":2},"NFKD":{"text":"e\u0301","codePoints":2,"utf16Units":2,"utf8Bytes":3}}

NFC、NFKC 将 e 加组合重音符转换为 U+00E9;NFD、NFKD 保留两个码点的规范分解。

分解预组合重音字符

input (ASCII JSON): "\u00E9"
{"original":{"text":"\u00E9","codePoints":1,"utf16Units":1,"utf8Bytes":2},"NFC":{"text":"\u00E9","codePoints":1,"utf16Units":1,"utf8Bytes":2},"NFD":{"text":"e\u0301","codePoints":2,"utf16Units":2,"utf8Bytes":3},"NFKC":{"text":"\u00E9","codePoints":1,"utf16Units":1,"utf8Bytes":2},"NFKD":{"text":"e\u0301","codePoints":2,"utf16Units":2,"utf8Bytes":3}}

NFD、NFKD 将 U+00E9 展开为 e 加组合重音符。显示可能相似,但字节长度会改变。

分解韩文音节

input (ASCII JSON): "\uAC01"
{"original":{"text":"\uAC01","codePoints":1,"utf16Units":1,"utf8Bytes":3},"NFC":{"text":"\uAC01","codePoints":1,"utf16Units":1,"utf8Bytes":3},"NFD":{"text":"\u1100\u1161\u11A8","codePoints":3,"utf16Units":3,"utf8Bytes":9},"NFKC":{"text":"\uAC01","codePoints":1,"utf16Units":1,"utf8Bytes":3},"NFKD":{"text":"\u1100\u1161\u11A8","codePoints":3,"utf16Units":3,"utf8Bytes":9}}

NFD、NFKD 把 U+AC01 分解为 U+1100 U+1161 U+11A8 三个组合字母,共占九个 UTF-8 字节。

审阅连字、宽度和圈号区别丢失

input (ASCII JSON): "\uFB03\uFF21\u2460"
{"original":{"text":"\uFB03\uFF21\u2460","codePoints":3,"utf16Units":3,"utf8Bytes":9},"NFC":{"text":"\uFB03\uFF21\u2460","codePoints":3,"utf16Units":3,"utf8Bytes":9},"NFD":{"text":"\uFB03\uFF21\u2460","codePoints":3,"utf16Units":3,"utf8Bytes":9},"NFKC":{"text":"ffiA1","codePoints":5,"utf16Units":5,"utf8Bytes":5},"NFKD":{"text":"ffiA1","codePoints":5,"utf16Units":5,"utf8Bytes":5}}

只有兼容形式会把 U+FB03 U+FF21 U+2460 转换为 ffiA1;仅凭结果无法恢复原来的区别。

长度不变但组合标记重排

input (ASCII JSON): "q\u0307\u0323"
{"original":{"text":"q\u0307\u0323","codePoints":3,"utf16Units":3,"utf8Bytes":5},"NFC":{"text":"q\u0323\u0307","codePoints":3,"utf16Units":3,"utf8Bytes":5},"NFD":{"text":"q\u0323\u0307","codePoints":3,"utf16Units":3,"utf8Bytes":5},"NFKC":{"text":"q\u0323\u0307","codePoints":3,"utf16Units":3,"utf8Bytes":5},"NFKD":{"text":"q\u0323\u0307","codePoints":3,"utf16Units":3,"utf8Bytes":5}}

所有形式都会把下点组合符放到上点组合符之前。序列改变,三种长度计数却完全不变。

保留 CRLF 与 emoji 序列

input (ASCII JSON): "A\r\n\uD83D\uDC69\u200D\uD83D\uDCBB\u2764\uFE0F"
{"original":{"text":"A\r\n\uD83D\uDC69\u200D\uD83D\uDCBB\u2764\uFE0F","codePoints":8,"utf16Units":10,"utf8Bytes":20},"NFC":{"text":"A\r\n\uD83D\uDC69\u200D\uD83D\uDCBB\u2764\uFE0F","codePoints":8,"utf16Units":10,"utf8Bytes":20},"NFD":{"text":"A\r\n\uD83D\uDC69\u200D\uD83D\uDCBB\u2764\uFE0F","codePoints":8,"utf16Units":10,"utf8Bytes":20},"NFKC":{"text":"A\r\n\uD83D\uDC69\u200D\uD83D\uDCBB\u2764\uFE0F","codePoints":8,"utf16Units":10,"utf8Bytes":20},"NFKD":{"text":"A\r\n\uD83D\uDC69\u200D\uD83D\uDCBB\u2764\uFE0F","codePoints":8,"utf16Units":10,"utf8Bytes":20}}

全部形式保留 CRLF、女性程序员 ZWJ 序列和爱心变体选择符。十个 UTF-16 单元对应八个码点、二十个 UTF-8 字节。

在 JSON 中保留不成对代理项

input (ASCII JSON): "A\uD800B"
{"original":{"text":"A\uD800B","codePoints":3,"utf16Units":3,"utf8Bytes":null},"NFC":{"text":"A\uD800B","codePoints":3,"utf16Units":3,"utf8Bytes":null},"NFD":{"text":"A\uD800B","codePoints":3,"utf16Units":3,"utf8Bytes":null},"NFKC":{"text":"A\uD800B","codePoints":3,"utf16Units":3,"utf8Bytes":null},"NFKD":{"text":"A\uD800B","codePoints":3,"utf16Units":3,"utf8Bytes":null}}

全部形式保留不成对的 U+D800。UTF-8 字节数为 null,原始复制和下载仍被阻止;ASCII JSON 精确保留字符串。

保持转义拼写为普通文字

input (ASCII JSON): "e\\u0301"
{"original":{"text":"e\\u0301","codePoints":7,"utf16Units":7,"utf8Bytes":7},"NFC":{"text":"e\\u0301","codePoints":7,"utf16Units":7,"utf8Bytes":7},"NFD":{"text":"e\\u0301","codePoints":7,"utf16Units":7,"utf8Bytes":7},"NFKC":{"text":"e\\u0301","codePoints":7,"utf16Units":7,"utf8Bytes":7},"NFKD":{"text":"e\\u0301","codePoints":7,"utf16Units":7,"utf8Bytes":7}}

输入由七个 ASCII 字符组成,其中包含一个反斜杠。工具不会把这种拼写当成组合重音符执行。

检查空输入

input (ASCII JSON): ""
{"original":{"text":"","codePoints":0,"utf16Units":0,"utf8Bytes":0},"NFC":{"text":"","codePoints":0,"utf16Units":0,"utf8Bytes":0},"NFD":{"text":"","codePoints":0,"utf16Units":0,"utf8Bytes":0},"NFKC":{"text":"","codePoints":0,"utf16Units":0,"utf8Bytes":0},"NFKD":{"text":"","codePoints":0,"utf16Units":0,"utf8Bytes":0}}

空字符串在四种形式下仍为空,码点数、UTF-16 单元数及 UTF-8 字节数都为零。

常见规范化误区

  • 只因 NFKC 转换更多字符就选择它,而没有检查排版或语义区别的丢失。
  • 误以为预组合字符、组合序列和 emoji 字素簇具有相同的 UTF-16 或 UTF-8 长度。
  • 把计数未变当成文字未变;规范重排可能保留全部长度却改变顺序。
  • 期待工具自动把 ASCII 的 \uXXXX 拼写解码成真实字符。
  • 把规范化当作安全净化、翻译、大小写折叠或身份证明。
  • 误以为转义已经移除秘密,从而直接分享完整报告。

限制与说明

  • NFC 先进行规范分解,再进行规范组合;NFD 进行规范分解。NFKC、NFKD 还应用兼容分解,NFKC 随后再组合。兼容变化通常不可逆,连字、宽度变体、圈号数字等区别可能合并。规范化不会去除重音、翻译、转写、转换字母大小写,也不能证明两段不同文字具有相同意图。
  • 实现使用当前浏览器运行时的 String.prototype.normalize 及其 Unicode 支持范围,不附带 Unicode 17 规范化数据库,也不承诺固定 Unicode 版本。运行时尚未认识的新字符映射可能产生不同结果;若新分配字符必须跨系统重现,请采用明确版本的下游实现。
  • 码点数不是可见字符数、字素簇数或显示宽度,一组 emoji 可能包含多个码点。补充平面字符占两个 UTF-16 单元。不成对代理项会保留,并作为一个诊断伪单元计数,但不是 Unicode 标量值;其 UTF-8 字节数不可用,原始复制及下载会被阻止,避免静默替换成 U+FFFD。 变化详情用共同码点前后缀之间的一个总括区间表示,不是最小编辑列表,区间中可能包含未变的部分。区间索引从零开始、结尾不包含在内,绝不拆开有效代理对。
  • 规范化不是内容净化、混淆字/同形字检测、恶意代码分析、标识符校验或安全判定。它不会任意删除隐藏字符、双向控制符、emoji 连接符或变体选择符。核心保留输入中的 CR 和 LF;浏览器粘贴或剪贴板可能在工具之外改变换行。需要精确换行时,优先使用严格文件导入及下载。
  • 处理仅在本地进行且有明确上限:输入最多 20,000 个 UTF-16 单元,UTF-8 文件最多 80,000 字节,每种规范化结果最多 360,000 个 UTF-16 单元,原文与四种形式合计最多 1,460,000 个单元。ASCII JSON 报告最多 10,000,000 个字符。不上传输入、不联网查询、不持久化。无效 UTF-8 文件会被拒绝,不用替换字符继续解码;开头 BOM 作为 U+FEFF 保留。处理或报告超限会明确报错,不会静默截断导出。ASCII 转义是可逆表示,不是脱敏或加密;完整报告包含原文及所有规范化文字,也可能包含隐私信息。

常见问题

应该选择哪种规范化形式?

以接收文本的系统约定为准。NFC 通常给出组合形式的规范表示,NFD 给出分解形式。NFKC、NFKD 还会合并兼容区别,需要额外检查语义。本工具提供并列比较,不宣称某一种形式永远正确。 不会。组合受到 Unicode 规则约束,部分字符被排除在组合之外。组合标记也可能只改变顺序,码点及字节数完全不变。请检查精确结果,不要仅凭长度判断是否发生变化。

NFKC 能让可疑文本变安全,或合并所有相似字母吗?

不能。兼容规范化不是完整安全机制,也不是混淆字符检测。例如拉丁字母和西里尔字母可能外形相似却仍然不同。请单独审查应用的标识符规则,并使用适合的安全工具。

为什么文本下载被阻止时仍能导出 JSON?

不成对 UTF-16 代理项无法在不替换内容的情况下编码为有效 UTF-8。诊断 JSON 使用 ASCII 转义保留原文和四种形式中的精确代码单元。转义并没有修复输入,也不表示文本安全。

会自动清理空格、emoji 和换行吗?

没有额外清理。兼容规范化可以转换具有兼容映射的字符,例如不换行空格;规范等价的规范化不会进行一般空白替换。CRLF、emoji 连接符和变体选择符不会被删除。导出前请检查实际码点。

相关工具