中文乱码如何被拦在提交前:AI Text Encoding Guard 实战
中文乱码如何被拦在提交前:AI Text Encoding Guard 实战
本文更新于 2026-07-26,内容对应 AI Text Encoding Guard v1.0.0。
中文文件经过一次 AI 编辑、批量替换或跨平台脚本处理后,为什么会突然变成乱码?
问题通常不在“中文”本身,而在文件读写链路:一段 UTF-8 字节被当成 GBK、GB18030 或 ISO-8859-1 解读,再以错误编码写回磁盘。Claude Code、Cursor、Copilot、Codex 等工具都可能经过终端、脚本和编辑器完成文件写入;只要其中一环没有固定编码,就可能触发或放大损坏。
AI Text Encoding Guard 的目标,是在这类问题进入提交或发布流程前,把可疑文件找出来,并对少数可逆样本尝试保守恢复。
先分清:有些乱码能恢复,有些不能
典型的 mojibake 往往仍保留原始信息:
错误显示:鐢ㄦ埛鐧诲綍鎴愬姛 |
如果只是“用错误字符集解释了同一组字节”,就有机会通过反向编码恢复。
但下面这种情况不同:
数据库连接失� |
� 是 Unicode 替换字符,通常意味着某些原始字节已经丢失。工具可以可靠地把它标记出来,却不能凭空找回缺失内容。遇到这类有损损坏,优先从 Git、编辑器历史或备份恢复。
它如何工作
扫描文件 → 启发式信号打分 → 标记可疑位置 → 尝试保守恢复 → 重新扫描 |
当前版本的核心流程是:
- 扫描项目目录,默认覆盖 20 种常见文本扩展名。
- 逐行检查七类启发式信号,并记录命中的位置和权重。
- 将有命中的文件列为可疑项,交给开发者检查。
- 使用
--fix-gbk时,尝试 UTF-8 / GB18030 双向候选恢复。 - 只有候选结果明显改善时才写入,并先创建
.bak.mojibake备份。
七类启发式信号
这些名称是项目内部为了便于理解而使用的分类,不是字符编码领域的标准术语。
| 项目内分类 | 常见来源 | 检测信号 | 权重 |
|---|---|---|---|
| 口字码 | 解码失败或数据丢失 | Unicode 替换字符 � |
+12 |
| 破标签 | 编辑过程破坏结构 | 损坏的 HTML 闭合标签 | +10 |
| 古文码 | GBK/GB18030 与 UTF-8 混用 | 已知高频乱码码点 | +2 |
| 锟拷码 | 多次错误转码 | 锟斤拷 等模式 |
+8 |
| 烫屯码 | 未初始化内存或调试填充值 | 烫烫烫、屯屯屯 重复 |
+6 |
| 问句码 | 不可表示字符被替换 | 中文后连续 ?? |
+8 |
| 符号码 | UTF-8 被当作单字节编码读取 | 拉丁扩展字符密集出现 | +2 |
“破标签”严格来说不是字符编码乱码,而是经常和乱码同时出现的结构损坏,因此也被纳入扫描。分数表示命中了多少可疑信号以及信号权重,并不是经过统计校准的“损坏概率”。
自动恢复为什么比较保守
--fix-gbk 不会看到可疑文本就直接替换,而是经过三道检查:
① 生成 UTF-8 / GB18030 双向恢复候选 |
这些门槛用于降低误修风险,但备份和评分都不能代替人工审查。自动恢复后仍应查看 diff,并再次运行扫描。
安装与直接运行
当前最稳妥的方式是从仓库安装:
git clone https://github.com/haodehaode378/text-encoding-guard.git |
安装后可以使用 CLI:
# 扫描项目 |
不安装也可以从仓库直接运行:
python scripts/check_mojibake.py --root ./src |
常用参数:
| 参数 | 作用 |
|---|---|
--json |
输出 JSON,方便脚本和 CI 消费 |
--fail-on-find |
发现可疑文件时返回退出码 2 |
--fix-gbk |
尝试对可逆样本进行恢复 |
--ext .sql |
添加额外扫描扩展名,可重复使用 |
--verbose / -v |
显示详细诊断 |
--quiet / -q |
减少控制台输出 |
项目运行时只依赖 Python 标准库,要求 Python 3.10 或更高版本。
接入 GitHub Actions
Action 必须先 checkout 目标仓库。当前存在的版本标签是 v1.0.0:
name: Encoding Guard |
还可以通过 fix-gbk 和 ext 输入控制自动恢复及额外扩展名。对 CI 来说,更推荐先只检测并阻止合并,再由开发者确认修复内容。
接入 Claude Code
如果项目中已经包含 scripts/check_mojibake.py,可以在 .claude/settings.json 中加入 PostToolUse hook:
{ |
如果使用的是已安装 CLI,则把命令换成 check-mojibake --root .。关键不是绑定某一个 Agent,而是让编码检查紧跟在文件写入之后。
使用边界
- 合法的生僻字、繁体字、拉丁扩展字符或乱码测试夹具可能触发启发式规则。
- 含
�的文本通常已经有信息损失,应优先回滚,而不是自动猜测。 .bak.mojibake是恢复保险,不代表修改结果一定正确。- 工具不会替代 Git diff、代码审查或真实页面预览。
- 默认会跳过
.git、node_modules、dist、build、虚拟环境和常见缓存目录。
file、uchardet 等工具更侧重识别文件编码;AI Text Encoding Guard 则把内容级启发式扫描、保守恢复、CI 卡点和 Agent hook 组合在一条工作流里。
仓库地址:https://github.com/haodehaode378/text-encoding-guard
问题和建议可以直接提交到 GitHub Issues。
