ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

Windows下codex中文乱码?用skill从源头根治GBK与UTF-8冲突

Windows下codex中文乱码?用skill从源头根治GBK与UTF-8冲突 说实话Windows 下用 codex 写带中文的文档第一次看到满屏???和“锟斤拷”的时候血压是真的压不住。明明代码逻辑没问题生成的 Markdown 打开一看全乱命令行里更是惨不忍睹。这个事不是个例几乎每个在 Windows 上跑 CLI 类 AI 工具的开发者都会撞上。我一直认为这不是 codex 的锅真正的问题出在 Windows 那套祖传编码体系上简体中文系统默认代码页是 GBK而 codex 这类工具产出的文本基本是 UTF-8两边字符集不在一个频道上乱码就成了必然。这篇博文要分享的是我自己整理并验证过的一个 codex skill专门用来在 Windows 下拦截和修复文档书写过程中的中文乱码问题。它不是玄学补丁而是把编码检测、转码规则、输出规范做成了 skill让 codex 在写任何含中文的文档前先过一遍流程。适合所有在 Windows 下使用 codex 或同类 AI 命令行工具写文档、写脚本、写配置的人。你不需要是编码专家照着装、照着用就行底层原理我也会讲清楚。1. 先定性乱码的根子在 Windows 的编码生态不在 codex1.1 两个字符集一场持续几十年的战争中文 Windows 从 DOS 时代延续下来简体中文系统的默认代码页是 936也就是我们常说的 GBK。GBK 用两个字节表示一个汉字在设计上兼容了区位码和 ASCII。而 codex 以及绝大多数现代开发工具用的都是 UTF-8它是 Unicode 体系下的变长编码英文占一个字节中文通常占三个字节。这两套编码最关键的区别不是“字节数不同”而是同一个汉字的字节序列完全不同。比如“中文”这两个字GBK 下是D6 D0 CE C4UTF-8 下是E4 B8 AD E6 96 87。当 UTF-8 的字节流被当成 GBK 去解码时系统会把每两个字节强行拼成一个“汉字”结果就是锟斤拷、烫烫烫这类经典乱码。反过来GBK 字节流被当成 UTF-8 解码通常直接报错或者出现一堆问号。理解了这一点再看所有乱码问题就清晰了乱码的本质永远是解码方式与编码方式不匹配。我用一个生活化的类比总结GBK 是中文世界的“本地话”UTF-8 是世界通用的“普通话”。Windows 里的 cmd、老版本记事本、各种国产软件默认只讲本地话codex 从出生就只讲普通话。两边各说各的能不乱吗。1.2 乱码发生的链路终端、文件、工具一个都不能少在 Windows 下codex 输出文字要经过三层每一层都可能出问题这也是为什么很多人修了半天发现“终端好了文件又乱”“文件好了换个软件打开又乱”。第一层是终端层。控制台代码页决定了 codex 打印到屏幕上的字符怎么被解析。Windows 默认代码页 936而 codex 往标准输出里写的是 UTF-8 字节流终端按 GBK 解码屏幕上自然全是乱码。这层出了问题现象是“在终端里看到乱码但文件内容可能是正常的”。第二层是文件层。codex 在写文件时用什么编码写入、有没有带 BOM直接决定这个文件在别的软件里能不能被正确识别。UTF-8 分为带 BOM 和不带 BOM 两种BOM 是文件开头的三个魔法字节EF BB BF用来告诉读取者“我是 UTF-8”。但很多 Windows 老程序不认识 BOM会把 BOM 当成内容的一部分读进去造成第一行出现奇怪的字符。第三层是工具层。你用什么软件打开文件就决定了文件以何种编码被展示。同一个 UTF-8 无 BOM 文件新版记事本能猜对并正常显示老版本记事本大概率按 GBK 读VSCode 又可能自动识别成 UTF-8。工具识别错了内容没坏但看起来就是乱码。这三层链路一旦串起来出问题排查就特别费劲。网上那些高频搜索词比如“vscode终端中文乱码”“cmd 运行中文程序输出乱码”“批处理脚本 echo 中文闪退”“devc 编译输出中文乱码”“qt 输出中文乱码 vs2019”“matlab 中文注释乱码”“Windows 高版本系统 notepad 记事本中文乱码”本质全都可以归纳到这条链路上。我们这篇聚焦 codex 场景但把链路理解透了那些问题也能顺手解决大半。1.3 不只是 codexWindows 下所有中文乱码都是同一个坑很多人在 codex 里遇到乱码后第一反应是“这工具不行”其实是冤枉它了。随便搜一下就能看到vscode 终端乱码、printf 中文乱码、devc 输出乱码、matlab 注释乱码这些跟 codex 八竿子打不着的场景问题根源高度一致。以 printf 中文乱码为例你写了个 C 程序源码保存成 UTF-8编译时编译器按本地代码页处理字符串字面量运行环境又是 GBK 的 cmd 窗口输出不乱才怪。vscode 终端乱码也一样终端用的 code page 还是 936shell 输出的 UTF-8 字符显示出来就是乱的。它们和 codex 乱码唯一的共同点就是生产端和消费端的编码不一致。这也是为什么我最终决定做一个 skill 而不是记一堆零散笔记。因为只解决 codex 的单点问题没有意义得让 codex 在 Windows 上从源头养成正确的编码习惯才能保证它生成的所有文档、脚本、配置文件都能顺利交付到其它工具链里。2. skill 是什么以及为什么用它来治乱码2.1 skill 不是 agent它的定位是“专业能力包”最近“skill”这个词在 AI 工具圈热度很高各种 skill 层出不穷比如数学建模 skill、workbuddy skill、仓颉 skill。很多人会把 skill 和 agent 搞混我先说下两者的关系。agent 是能自主拆解任务、调用工具、执行动作的主体你可以把它想成一个“全能实习生”。而 skill 是给这个实习生用的“岗位操作手册”或者“专业能力包”它规定了在特定任务下应该遵循的流程、规范和注意事项。同一个 agent 可以挂载很多个 skill同一个 skill 也可以被不同的 agent 复用。拿 codex 来举例。codex 本身就是一个 agent它能理解你的自然语言指令、编辑文件、执行命令。当你给它挂上“Windows 乱码修复 skill”后它在执行写文档任务时就会自动参考 skill 里的编码规则而不是靠模型临时发挥。模型未必记得住 Windows 下 GBK 和 UTF-8 的那些细节但 skill 里白纸黑字写清楚了它只需要照着做。2.2 用 skill 治乱码的好处从“每次手动修”到“每次自动防”如果你只是偶尔一次乱码手动执行一下chcp 65001切代码页就够了。但 codex 写文档是日常操作每次都要记得切换、每次都要盯着输出检查太反人类了。skill 的核心价值在于把规范和决策树固化到 codex 的工作流里。只要触发条件命中codex 就会自动执行 skill 里的流程先检查当前系统编码状态再根据输出目标选择合适编码文件生成后做二次验证遇到已有乱码文件会先备份再转码。整个过程不需要你干预从“事后修”变成了“事前防”。而且 skill 是可维护的。你在使用过程中发现了新的编码坑直接编辑 SKILL.md加一条规则就行。这比在系统里改一堆环境变量、写一堆批处理要干净得多也方便在不同机器之间同步。2.3 codex skill 的大致工作机制codex 通常在用户主目录下有一个.codex配置目录Windows 下一般是C:\Users\你的用户名\.codex\。skill 就放在这个目录下的skills子目录里每个 skill 是一个独立文件夹核心文件是SKILL.md。当 codex 在对话中识别到某个 skill 被启用或与当前任务相关时它会把SKILL.md的内容加载进上下文作为执行指令的一部分。SKILL.md可以写触发条件、执行流程、规范规则还可以引用辅助脚本。codex 会按这些步骤来执行而不是自由发挥。需要提醒的是不同版本的 codex 对 skill 的触发方式和配置项细节可能有差异。我在下面的实操中会给出一个通用的目录结构和配置方式你按照自己安装的版本微调即可。重点是理解思路不要死记路径。3. 实战写一个专治 Windows 中文乱码的 skill3.1 目录结构与核心文件我设计的这个 skill 叫fix-windows-encoding目录结构如下~/.codex/skills/fix-windows-encoding/ ├── SKILL.md ├── scripts/ │ ├── check_encoding.py │ └── fix_mixed_encoding.pySKILL.md是 skill 的核心指令文件负责告诉 codex“在什么场景下启用、按什么规则输出、遇到乱码如何修复”。scripts目录下放两个 Python 脚本一个用于编码环境检查和单文件编码识别另一个用于批量转码和备份。Python 在 Windows 下基本是标配如果你机器里实在没有 Python也可以用 PowerShell 替代但 Python 的编码探测能力更干净利落。3.2 SKILL.md 的核心指令编写以下是一个可以拿来就用的 SKILL.md 模板它基于 codex 常见的 SKILL 机制编写具体字段可能需要根据你的 codex 版本做微调--- name: fix-windows-encoding description: 在 Windows 环境下编写文档、脚本、日志、配置文件时自动处理和预防中文乱码问题。适用于 codex 生成或修改 markdown、txt、bat、ps1、json、log 等文件。 trigger: 当任务涉及创建、修改或修复包含中文的文档、脚本、配置文件或用户明确提到乱码、编码、GBK、UTF-8 等问题时自动启用本 skill。 version: 1.0.0 --- # 执行流程 1. 编码环境检测 - 记录当前控制台代码页chcp 输出结果 - 检查目标文件当前编码状态优先用 scripts/check_encoding.py 识别 2. 输出编码规范 - markdown、txt、log、json、yaml、env 文件默认使用 UTF-8 无 BOM - bat / cmd 批处理脚本使用 GBK 或 UTF-8 无 BOM严禁带 BOM - PowerShell 脚本使用 UTF-8 无 BOM - 如果目标交付对象明确只支持 ANSI/GBK则转 GBK 并在交付说明中注明 3. 乱码修复流程 - 修复前先备份原文件为 .bak - 用 scripts/check_encoding.py 探测原文件编码 - 根据探测结果用 scripts/fix_mixed_encoding.py 转码为指定编码 - 转码完成后再次用 check_encoding.py 验证 4. 强制规则 - 不修改系统级区域设置 - 不要求用户开启 Beta 版 UTF-8 全局支持 - 生成文件时主动在最终交付说明里注明该文件的编码格式这份 SKILL.md 的核心思想是“先检测、再决策、后操作”。codex 读到这里时会先跑检测脚本再根据文件类型决定编码最后才动手写内容。这样一来codex 就不会再拍脑袋乱写编码了。3.3 编码巡检脚本让 codex 先诊断再动手check_encoding.py的作用有两个一是查看当前系统的编码环境二是识别单个文件的编码类型。脚本内容如下import os import sys import locale import subprocess from pathlib import Path def detect_encoding(filepath: str) - str: raw Path(filepath).read_bytes() if raw.startswith(b\xef\xbb\xbf): return utf-8-sigUTF-8 带 BOM if raw.startswith(b\xff\xfe): return utf-16-leUTF-16 小端 try: raw.decode(utf-8) return utf-8无 BOM except UnicodeDecodeError: pass try: raw.decode(gbk) return gbk/ansi except UnicodeDecodeError: return unknown无法识别 if __name__ __main__: print(Python 默认编码:, sys.getdefaultencoding()) print(locale 首选编码:, locale.getpreferredencoding(False)) console_enc os.device_encoding(0) or 未知 print(控制台编码:, console_enc) chcp_result subprocess.run( [chcp], capture_outputTrue, textTrue, encodinggbk, errorsreplace ) print(chcp 输出:, chcp_result.stdout.strip()) if len(sys.argv) 1: for path in sys.argv[1:]: if Path(path).exists(): print(f{path} - {detect_encoding(path)}) else: print(f{path} - 文件不存在)有几个细节我解释一下。chcp在 Windows 下的输出是 GBK 编码的所以用encodinggbk, errorsreplace读取避免子进程返回乱码导致误判。locale.getpreferredencoding(False)拿的是系统区域设置下的首选编码简体中文系统通常是cp936。os.device_encoding(0)返回当前标准输入设备的编码在终端里运行时如果是 65001说明代码页已经切到 UTF-8 了。这个脚本还有一个隐藏价值codex 执行命令时会读取它的输出如果你不告诉它“chcp 输出要用 GBK 解码”它很可能自己就被乱码干扰了判断。脚本提前处理好了这个坑codex 拿到的就是干净、可解析的信息。3.4 乱码文件批量修复脚本先备份再转码fix_mixed_encoding.py负责真正动手修复已有乱码文件。它的设计原则很朴素不知道原编码就探测探测不出来就跳过改之前必须先备份。import sys from pathlib import Path def smart_convert(filepath: str, target: str utf-8) - None: p Path(filepath) raw p.read_bytes() if raw.startswith(b\xef\xbb\xbf): src utf-8-sig elif raw.startswith(b\xff\xfe): src utf-16-le else: try: raw.decode(utf-8) src utf-8 except UnicodeDecodeError: try: raw.decode(gbk) src gbk except UnicodeDecodeError: print(f跳过{filepath}无法可靠识别编码) return text raw.decode(src) if target utf-8: new_data text.encode(utf-8) elif target gbk: new_data text.encode(gbk) else: raise ValueError(f不支持的目标编码: {target}) backup p.with_suffix(p.suffix .bak) p.rename(backup) p.write_bytes(new_data) print(f已转换 {filepath}: {src} - {target}原文件备份为 {backup.name}) if __name__ __main__: if len(sys.argv) 2: print(用法: python fix_mixed_encoding.py 文件或目录 [目标编码]) sys.exit(1) target sys.argv[2] if len(sys.argv) 2 else utf-8 path Path(sys.argv[1]) if path.is_file(): files [path] else: files list(path.rglob(*.txt)) list(path.rglob(*.md)) list(path.rglob(*.log)) list(path.rglob(*.json)) for f in files: smart_convert(str(f), target)这里有个容易忽略的点p.rename(backup)执行的是“原文件改名成备份”然后再用原名写入新文件。这样做的意图非常明确——宁可多留一份.bak也不要把唯一副本转坏了。另外转码方向的选择要谨慎。如果文件本来是 UTF-8 无 BOM内容里却还有大量 GBK 字样说明这个文件被多次错误转换过已经发生了“信息折叠”这种情况下机械转码救不回来需要回到最早期的版本重新处理。skill 里的规则也提醒了 codex遇到不确定的文件不要硬转先备份后交给用户确认。3.5 安装与启用三步把 skill 挂到 codex 上安装过程不复杂三步搞定。第一步创建 skill 目录。在 Windows 的 PowerShell 或 cmd 里执行mkdir %USERPROFILE%\.codex\skills\fix-windows-encoding\scripts第二步把编写好的SKILL.md放到fix-windows-encoding目录下把两个 Python 脚本放到scripts子目录。文件结构跟上面展示的一致即可。第三步在 codex 会话中启用。最简单的方式是直接告诉 codex“本次会话启用 fix-windows-encoding skill遵照 SKILL.md 处理所有文件输出。” codex 会自动加载对应 skill。如果你希望每次会话都自动启用可以在 codex 的config.toml里加上类似下面的配置具体字段名以你自己安装的版本实际支持为准# ~/.codex/config.toml [skills] enabled [fix-windows-encoding]配置完成后建议做一个快速验证让 codex 写一个包含中文的 markdown 文件然后自己用 Python 或 VSCode 打开检查编码。能正常显示说明 skill 已经在干活了。4. 高级配置从“会修”到“不生乱”4.1 为什么默认挑 UTF-8 无 BOM而不是有 BOM 的 UTF-8很多 Windows 老用户习惯了“带 BOM 的 UTF-8”因为记事本能通过 BOM 快速识别文件编码。但在跨平台场景下BOM 带来的麻烦远大于它带来的便利。首先是兼容性问题。Linux 和 macOS 下的很多工具不认 BOM会把EF BB BF当作真实字符读进去导致文件第一行多出一个不可见字符轻则格式错乱重则脚本解析报错。Git 也经常跟 BOM 过不去导致 diff 显示异常。其次是复制粘贴时 BOM 容易残留比如从一个 UTF-8 带 BOM 文件里复制一段代码贴到另一个无 BOM 文件里第一行前面悄悄多了一个零宽字符排查起来非常隐蔽。所以现代开发实践的主流是 UTF-8 无 BOM。新版 Windows 记事本Windows 10 1903 以后已经默认用 UTF-8 无 BOM 读写VSCode 也默认如此。唯一要注意的是个别老旧软件仍然“见 BOM 才认 UTF-8”遇到这种情况再用 4.2 的决策表单独处理不要为了少数场景牺牲全局默认。4.2 按目标场景定编码的决策表在 SKILL.md 里我给了 codex 一张编码决策表让它在不同交付场景下能自主选择输出目标推荐编码原因Markdown / txt / log / json / yamlUTF-8 无 BOM跨平台最友好Git 无冲突现代编辑器默认批处理 .bat / .cmdGBK 或 UTF-8 无 BOM带 BOM 的 UTF-8 会导致 cmd 解析异常中文 echo 可能闪退PowerShell .ps1UTF-8 无 BOMPowerShell 7 默认一致PS 5.1 也兼容配置文件 .env / config.iniUTF-8 无 BOM避免特殊字符被误读面向老软件、老设备的接口文件GBK目标系统只支持 ANSI 时必须顺应对方C/C 源码文件UTF-8 无 BOM注释前检查编译器选项防止源码编码与编译器预期不一致这张表不是死的它在传递一个核心思路编码不是越“高级”越好而是越“合适”越好。codex 有了这张表就不会在写批处理时自作主张搞出 UTF-8 带 BOM 的坑文件。4.3 再固化两个兜底规则除了编码选择我在 SKILL.md 里还写了三条兜底规则它们来自我踩过的真实教训。第一条所有 bat/cmd 脚本一律禁止使用 UTF-8 带 BOM。cmd 的老式解析器对 BOM 的处理极其脆弱一个带 BOM 的 bat 脚本哪怕内容完全正确也可能在中文字符后面出现命令截断、闪退、乱码。要么 GBK要么 UTF-8 无 BOM二选一没有第三个选项。第二条codex 生成包含中文文件名的文件时尽量使用 ASCII 或拼音命名。Windows 文件系统本身支持 Unicode 文件名但跨系统传输、压缩、打包时中文文件名很容易变成乱码。这个约束让交付物在 Linux、macOS、Windows 之间流转时更省心。第三条每次交付含中文的文件时codex 必须在说明里注明编码格式。这一步非常反直觉但很管用。收文件的人如果知道“这是 UTF-8 无 BOM”就不会用 GBK 去打开沟通成本直线下降。5. 排查清单与踩坑实录5.1 直接可用的乱码速查表先把最实用的速查表放出来遇到乱码时对照着做能解决大部分问题乱码现象可能原因快速处理codex 在终端输出全是问号或乱码终端代码页仍是 936codex 输出 UTF-8重开终端执行chcp 65001或在 Windows Terminal 里运行生成的 .md 文件用记事本打开正常VSCode 乱码VSCode 自动猜测编码失败右下角点击编码手动选 UTF-8 或 GBK生成的 .md 文件 VSCode 正常记事本乱码文件是 UTF-8 无 BOM老记事本按 GBK 读升级到新版记事本或改用带 BOM 的 UTF-8bat 脚本含中文就闪退或乱码bat 文件带 BOM或 cmd 代码页与文件编码不匹配保存为 GBK 或 UTF-8 无 BOM并在脚本开头加chcp 65001 nulPowerShell 脚本执行后中文乱码PS 5.1 默认输出编码与脚本文件编码不一致脚本保存为 UTF-8 无 BOM输出时用Out-File -Encoding utf8文件中出现“锟斤拷”UTF-8 字节被按 GBK 解码再次按 GBK 编码后形成折叠找回原始 UTF-8 文件或用转码脚本反向处理前提是信息未损坏文件中出现“烫烫烫”未初始化内存的调试占位符常见于 C/C不是编码问题是代码问题检查内存分配和字符串初始化这张表我让 codex 也看一遍它以后排查问题时思路会更清晰。表中的最后两行尤其是“锟斤拷”是很多人的知识盲区。它不是某种特殊字符而是“UTF-8 解码失败按 GBK 硬解又被编码回去”后的产物属于典型的二次编码事故。5.2 几个我踩过的真坑光有速查表不够我把实战中真正踩过的坑细讲一下这些细节常规文档里不会写。第一个坑chcp 65001只对执行命令之后启动的新进程生效对当前已经打开的终端窗口无效。很多人执行完chcp 65001发现终端还是乱就开始怀疑人生。正确操作是切换代码页后重开一个终端窗口或者直接改用 Windows Terminal——它对 Unicode 的支持比传统 conhost 好太多字体渲染也更稳。我现在基本不用老的 cmd 窗口跑 codex全部交给 Windows Terminal。第二个坑PowerShell 5.1 和 PowerShell 7 的默认输出编码完全不一样。PowerShell 5.1 里的Out-File默认是 UTF-16 LESet-Content默认是 ANSI也就是 GBK而 PowerShell 7 默认是 UTF-8 无 BOM。如果你的系统里同时存在这两个版本的 PowerShellcodex 执行命令时生成的文件可能编码各异。我的 skill 之所以强制指定转码脚本就是为了摆脱 PowerShell 默认行为的不确定性让编码完全可控。第三个坑手动开启系统的 Beta 版 UTF-8 支持在区域设置里勾选“使用 Unicode UTF-8 提供全球语言支持”确实能从根本上解决代码页冲突但代价很大。开启后部分老软件会直接显示乱码甚至无法运行一些依赖 ANSI 编码的协议栈也会出问题。我试过一段时间最后因为几个工业软件全崩只能回退。所以 skill 里我明确写了一条不修改系统级区域设置不要求用户开启 Beta 版 UTF-8。这是最稳妥的路线。第四个坑VSCode 打开乱码文件时别急着改全局配置右下角点一下编码按钮选择“通过编码重新打开”再试“UTF-8”或“GBK”即可。很多时候两秒钟就恢复改配置文件反而容易被全局设置误伤其它文件。5.3 验证修复效果别信肉眼信字节乱码修没修好不能靠肉眼扫一眼就说“行了”因为一部分乱码字符可能恰好被错误解码成看起来正常的汉字序列。最靠谱的方式是看文件头字节和实际解码结果。如果你装了 Python直接调用我们 skill 里的巡检脚本python ~/.codex/skills/fix-windows-encoding/scripts/check_encoding.py test.md脚本会输出当前环境编码和该文件的识别结果。如果你想手动验证文件头可以用 PowerShell 的format-hex命令看前几个字节format-hex test.md | Select-Object -First 5如果你看到文件开头是EF BB BF说明是 UTF-8 带 BOM直接看到中文字符的 UTF-8 字节序列就是无 BOM如果识别出来是 GBK 的D6 D0 CE C4之类的双字节序列说明文件实际是 GBK。关键判断逻辑就是文件内容到底想用什么编码与外界对话和终端/编辑器以为它是什么编码这两者是否一致。一致就是正常不一致就是乱码。我在实际使用中的体会是不管 skill 写得多细最后都要落到两个系统级兜底能切 UTF-8 的场景坚决切不确定时就先备份再转码。codex 本身只是一个工具它对编码毫无“常识”可言全靠 skill 喂给它的规则。所以这个 skill 的维护价值很高每次遇到新编码坑往 SKILL.md 里补一条规则后面就再也不会踩第二次。最后再分享一个小细节codex 如果读到了带 BOM 的 UTF-8 文档它给出的修改结果很容易带上 BOM 残留导致文件第一行隐性出错。我在 skill 里规定所有输出必须是 UTF-8 无 BOM这个小规则帮我省掉了至少十次莫名其妙的“文件第一行解析失败”。你如果也做同样的配置大概率也会觉得这一条特别值。
返回列表