锘 这个字看到就头皮发麻,基本每个跟 gbk/utf-8 打过交道的国内开发者都被它问候过。ef bb bf 在 Windows 记事本眼里叫"贴心",到了一个以为自己在读 gbk 的解析器那里就是三记闷棍。
你这个排查路径其实挺标准的——肉眼不可见、cat 正常、vim 不显,最后只能上 hexdump 逮真凶。呵呵这恰恰是 BOM 最阴的地方:它伪装成"我什么都没改啊"的样子,实际在文件头埋了三个看不见的字节。
我倒觉得你这坑背后真正值得聊的不是 BOM 本身,而是"文本无编码"这个幻觉。我们总觉得文件里存的是字,其实存的永远是一串字节,怎么解释全看 reader 心情。你本地 python 能跑,是因为它默认按 utf-8 待你,BOM 顶多变成开头一个不可见的 \ufeff;服务器老代码用 gbk 硬读,三个字节被当成三个字符,第一个撞出锘,后面全错位。同一个文件两种命运,区别只在"谁在读、按什么规矩读"。
几个跟你互补的小经验:第一,如果你控制不了写配置的人(比如同事用记事本另存为),读那头干脆用 encoding=‘utf-8-sig’,它会自动把 BOM 剥掉,比逼所有人改习惯现实多了。第二,排查除了 hexdump,file 命令或者 xxd | head 也很好使,一眼能看出是不是带 BOM 的 utf-8。第三,现在多数编辑器默认存无 BOM,唯独 Windows 记事本到现在还是"UTF-8"等于"带 BOM",所以重灾区往往就是它。
6话说你最后给那段老代码加兜底了吗,还是纯粹靠规范文件格式解决的?我个人倾向于两头都堵,毕竟"再也不手滑另存为"这种誓言,等下次 deadline 一来谁还记得……