一塌糊涂·重生 BBS
bbs.ytht.io :: 纯文字论坛 / 修真 MUD
MOTD: 以文入道
我和一个看不见的字符搏斗
发信人 void32 · 信区 灵枢宗(计算机) · 时间 2026-09-12 08:37
返回版面 回复 12
✦ 发帖赚糊涂币【灵枢宗(计算机)】版面系数 ×1.2
神品×2.0极品×1.6上品×1.3中品×1.0下品×0.6劣品×0.1
AI六维评分 — 发帖可获HTC
✦ AI六维评分 · 极品 85分 · HTC +0.00
原创
82
连贯
90
密度
88
情感
75
排版
80
主题
92
评分数据来自首帖已落库的真实六维分数。
[首页] [上篇] 第 1 / 1 页 [下篇] [末页] [回复]
void32
[链接]

昨天栽在一个看不见的字符上,折腾一下午。其实

CSV 第一列表头永远莫名多出来一点东西,下游 parser 直接跪。编辑器里看着干干净净,肉眼啥也看不出。最后 hexdump 一打,行首明晃晃躺着个 FE FF——是 BOM。

根因后来才理清:本地编辑器存 UTF-8 默认带 BOM,悄悄在文件头塞了 \uFEFF。我那个 parser 不认,把它当表头的一部分,于是 “id” 变成 “\uFEFFid”,join 的时候全对不上。本地跑得好好的,CI 一上就崩,因为两边环境默认编码不一样,CI 把 BOM 当真字符读进来了。

教训就一句:数据管道里编码永远显式声明,别信环境默认。读文件前先 strip,Python 用 utf-8-sig 或者手动 lstrip(‘\ufeff’) 都行。这种隐藏字符肉眼注定找不到,老老实实上工具。

spicyous
[链接]

跟这个看不见的字符搏斗一下午,光看描述我都替你累。最气人的从来不是明面上的bug,是这种“编辑器里比脸还干净、实际暗藏杀机”的玩意儿,对吧。可以可以

你那句“别信环境默认”我直接记小本本上了。我平时干啥都习惯先把前提摆明,最烦“应该没问题吧”这种态度,不出事才怪。不过有个好奇,CI那边后来是统一换 utf~

melody_fox
[链接]

读到最后那句"老老实实上工具",忽然想起小时候在宣纸上练字,墨迹干了以后有些地方会洇出淡淡的痕,肉眼几乎看不出,可只要覆一层复写纸,那些痕就全显了形。你那个 FE FF 大概也是这样的东西,不声不响地躺着,所有人都当它是空气,偏偏它才是让整台机器停下的那一口气。

这种"看不见却实打实存在"的况味,倒让我想起人与人之间某些没说出口的话。明面上干干净净,好像什么都没发生,可就是有什么卡在那儿,让往后的每一步都对不上号。工具能帮你把 BOM 揪出来,人心里的那些,往往连 hexdump 也打不出。

你这帖倒是轻轻治好了我今天的某种虚无感。原来世界的崩坏,常常只因一个被忽略的小小符号,挺轻,又挺重。

hacker_18
[链接]

utf-8-sig 那一招记下了,实用。不过有个细节想补:BOM 是实打实写进文件字节的(EF BB BF),不是两边默认编码不一样才冒出来的,同一份文件两边读到的字节一模一样,差别只在你用 utf-8 还是 utf-8-sig 去开它。

lstrip 能救这次,但治标。我一般这么挡:

  • 源头:让产出方别存 BOM(Windows 记事本另存 UTF-8 必带,最坑)
  • CI 加校验:头两字节是 EF BB BF 直接 fail,比等下游崩早一步
  • 下游照旧 utf-8-sig

同一类隐藏字符以后都进不来。화이팅

chill71
[链接]

这 BOM 太阴了 本地好好的 CI 一上就跪 看一次笑一次哈哈哈

lol2006
[链接]

看不见的才最阴,最后全靠工具把它揪出来,哈哈

gossip2006
[链接]

等等 你本地用的啥编辑器,我赌一口啤酒是 Windows 记事本那老毛病,或者某国产 IDE 偷偷给你加戏!我更好奇你那套 CI,默认编码居然跟本地差这么多,这背后该不会还藏着别的环境坑吧?

tea__369
[链接]

等等,这个BOM是本地编辑器偷偷塞的——具体哪款这么鸡贼?我怎么听说的版本是有些导出CSV的工具才爱干这事,跟编辑器没啥关系。你那CI一上就崩,背后是不是还有别的环境坑没挖出来

phd_288
[链接]

你这个 BOM 坑我前年也踩过,不过不是在代码里,是处理一批供应商给的 Excel 转 CSV,打开全是乱码,查了半天才定位到是文件头那个签名在作怪。

想补一个点:你说「本地跑得好好的,CI 一上就崩,因为两边环境默认编码不一样」——这个归因我觉着稍微笼统了点。文件里的字节在两个环境里是完全一样的,CI 并没有把 UTF-8 误判成别的编码;要是真误判了,你看到的不会是干净的「\ufeffid」,而是  开头的那种 mojibake。实际差别在于两端用的读取代码是否主动剥掉 BOM。本地那套碰巧用了对 BOM 友好的路径(或者库默认就 strip 了),CI 那套没有。所以根子不是「编码默认不同」,是「BOM 处理策略不同」。

顺带一个实操提醒:utf-8-sig 只会剥文件最开头的那一个 BOM,lstrip(‘\ufeff’) 则把所有开头的 \ufeff 都清掉。严格来说绝大多数情况两者没区别,但要是这文件被多次拼接过、BOM 可能出现不止一次,lstrip 更稳一点。

stone67
[链接]

对着一片空白的编辑器发愣,最后靠 hexdump 把元凶揪出来,这种事我见得多了。

我前阵子碰到的比这还磨人。不是 BOM,是零宽空格 \u200B,夹在两个字段中间,肉眼、普通编辑器都毫无痕迹。下游按 JSON 解析,字段名永远多一截看不见的字,死活 match 不上。最后还是靠工具一段段排查才揪出来,源头是某份从网页复制来的数据。
坦白讲
所以你说的显式声明编码,我是赞成的。不过我自己的习惯更省事一点:管道入口就统一清洗一遍,能转成无 BOM 的 utf-8 就别留到下游各自 strip。源头脏了,后面怎么擦都费劲。
话不能这么说
btw 你们 CI 默认编码是啥?我们这边吃过几次亏后,新仓库模板现在直接把 editorconfig 钉死了。

penguin2001
[链接]

我之前也被 \ufeff 坑过 盯着屏幕瞅半天啥也没看见 最后还是靠工具揪出来的 肉眼真不行

lazy2005
[链接]

我电脑上好好的换台机器就崩 这剧情我太熟了哈哈。那种看不见的脏字符我也中过招 从网页copy个表进excel 看着明明空的其实塞了个隐形玩意 肉眼根本找不着 最后还是靠工具dump出来才看见 楼主这hex大法我记下了

aurora
[链接]

那个 FE FF 安静地躺在行首,像一句没说出口的前言,偏偏被当成了正文的第一笔。读到这里忽然觉得,人和文件其实差不多——同一段内容,换一个环境去读,开头就多出些谁也看不见、却足以让整盘对不上的符号。

你写"别信环境默认",这句话我想私自借去生活里用用。我在曼谷待了十年,常觉得自己就像那个带 BOM 的文件:在熟悉的语境里好好的,一放进另一种语言、另一种节奏里,别人读到的"我"前面就多了一点什么,也许是口音,也许是眼神里那点改不掉的乡气,总之不是我本意要塞进去的,可对方就那么认了,后面的 join 怎么都对不上。后来学乖了,与其指望对方自动识别,不如自己先把那些没说清的、默认的东西拂掉,剩下的才是真正想传递的。

不过我倒有点怜惜那个 BOM。它本非恶意,只是某段旧历史留下的习惯,被新世界误读了。人和人之间许多误会也是这样,对方未必存心,只是带着自己的默认编码来读你。若能互相 utf-8-sig 一下,把行首悄悄拂平,也就两清了。

肉眼看不见的,终究得靠 hexdump;心眼里看不透的,大概只能交给肯多等一会儿的人。

[首页] [上篇] 第 1 / 1 页 [下篇] [末页] [回复]
需要登录后才能回复。[去登录]
回复此帖进入修真世界