前两天写了个小脚本读csv,本地跑得好好得,丢服务器上中文全变口口口,文件头还藏着仨看不见的字符。折腾半天才搞明白,是Windows记事本默认存成UTF-8 BOM,那三个字节 ef bb bf 跟着混进来了。
我那脚本老老实实按utf-8读,结果第一列名字前多了个隐形标记,字符串比对全对不上,我还以为服务器环境闹鬼了哈哈。拿hexdump一瞅才反应过来。
现在学乖了,本地都用不带BOM的编辑器,读文件前顺手strip掉前三个字节。这玩意儿感觉就是专门蹲着坑不熟悉的人,你们被它绊过没有……
前两天写了个小脚本读csv,本地跑得好好得,丢服务器上中文全变口口口,文件头还藏着仨看不见的字符。折腾半天才搞明白,是Windows记事本默认存成UTF-8 BOM,那三个字节 ef bb bf 跟着混进来了。
我那脚本老老实实按utf-8读,结果第一列名字前多了个隐形标记,字符串比对全对不上,我还以为服务器环境闹鬼了哈哈。拿hexdump一瞅才反应过来。
现在学乖了,本地都用不带BOM的编辑器,读文件前顺手strip掉前三个字节。这玩意儿感觉就是专门蹲着坑不熟悉的人,你们被它绊过没有……
这仨小鬼我也被它坑过,当时也是对服务器环境一通瞎猜,最后hexdump一瞅差点把键盘砸了。你那个读前顺手strip的做法其实挺实在,比我在论坛翻三页老帖找答案省事多了,下次我也这么干。
这仨小鬼我可算领教过,之前比对全对不上,拿hexdump一瞅才发现猫腻~
ef bb bf 这仨字节我现在看一眼就ptsd 记事本真坑
ef bb bf这串我现在看都条件反射了 之前帮人传文件也撞上过 本地打开好好的对面收到全乱码 我俩对着屏幕琢磨半天还以为谁电脑中邪 后来才晓得是记事本偷偷加戏
现在凡是存中文文本我都先确认有没有BOM 看见Windows记事本就警惕三分 楼主这帖该置顶 省得后来人一个个被仨小鬼吓到
服务器闹鬼那段我真信了,但说真的你绝不是头一个。我前阵子处理一份导出的csv也踩过这坑,第一列表头死活对不上,对着屏幕怀疑人生半小时,最后hexdump一开,好家伙,仨小鬼蹲最前头。
strip前三个字节这招我也在用,不过更懒人的办法是读的时候直接指定encoding='utf-8
第一列名字前藏着个隐形标记,读到这里我竟有些出神。世间的许多误会大约也如此,谁也没有说错什么,只是开头悄悄多了一点什么,往后整串的字符便再也对不上了。
哈哈哈这仨小鬼我也撞见过,当时看着满屏口口口真以为是环境闹鬼,对着屏幕骂了半天。现在传文件前都先扒一眼开头那几个字节,谁爱带BOM谁带哈哈哈
直接strip前三个字节这招不太严谨,万一文件本来就没有BOM,开头那三个字节可能就是正经数据,一刀下去反而把内容砍坏了。稳妥点还是先比对是不是真有 ef bb bf 再决定去不去,或者干脆用能自动识别BOM的reader读。
这坑太经典了,基本每个处理过中文文件的人都得交一次学费。我也被 EF BB BF 坑过,补几个你那个解法里值得留意的点。
你"读前顺手 strip 掉前三个字节"这个写法,如果是对每个文件都无脑砍前三个字节,其实有隐患。万一哪天读进来的是个没带 BOM 的正常 UTF-8 文件,前三个字节是真实数据,你就把人家的有效内容砍掉了。稳妥做法是先判断 startswith(b’\xef\xbb\xbf’),命中了再去掉,没命中原样走。简单说
Python 有现成解法,open 的时候用 encoding=‘utf-8-sig’,解码器认得 BOM 会自动吞掉,碰上不带 BOM 的文件也不受影响。比手写 strip 干净,也不用担心自己哪天把边界情况漏了。
再说根因。BOM 在 UTF-8 里本来是可选的,纯属微软记事本自己加的戏。你本地用记事本存成 UTF-8 with BOM,服务器是标准无 BOM 环境,两边行为不一致才暴露。治本就是你说的换编辑器,但凡团队里还有人用记事本改配置,这个雷就一直在那蹲着。
还有个更容易忽略的:U+FEFF 这个字符本身不是只能待在文件头,它作为零宽不换行空格,理论上能出现在字符串中间,做比对时照样悄悄对不上。所以读入端用 utf-8-sig 兜个底之外,最好数据源那头就把编码规范死。
你们服务器跑的啥环境?我猜是 Linux 上的 python3 默认 utf
读到那句"闹鬼了",忍不住莞尔。那三个字节真像生活里某些时刻——什么都没写错,事情却悄悄生了岔,回头翻检,才发现开头早被人添了几道看不见的折痕。ef bb bf,三个站错位置的逗点,句子就念歪了。我现在也学着,遇事先掸掸边上的灰,再看它真正写着什么。
那三个字节,总让我想起檐角悬着的三滴将落未落的雨——你知道它们在,却总也看不见,直到衣裳洇湿了才恍然。
你说"服务器闹鬼",这形容倒贴切得很。BOM 本意原是善意的,像有人在文件头顶贴了张便笺:“喂,我真是 UTF-8。” 可这张便笺,到了讲究简洁的 Unix 世界里,反倒成了不速之客。Windows 记事本一片好心把它塞进去,服务器那头却照老规矩认字,于是第一列的名字前头,便悄悄多了道谁也瞅不见的门槛。字符串比对,比的不是字,是字连同它头上一道 invisible 的影。
Genau,这大概是最磨人的地方:我们总以为是对方变了,是环境闹鬼,是服务器水土不服,却很少先低头看看,自己带来的行囊里,是不是早就藏着这么一粒看不见的砂。
我后来学了个更省心的法子,不删字节,而是让读的人先认下那张便笺——多数语言如今都有能自动吞掉 BOM 的打开方式,省得手动 strip 时手一抖,把该留的也去了。当然你那招也灵,野径总不如大路稳当罢了。
怎么说呢
说到底,这些蹲在门口的小鬼,专挑我们最笃定的时候下手。下次再撞见口口口,大约会先笑一笑,想起帖子里这仨小鬼,然后慢悠悠去翻文件头。
你们遇过更刁钻的没有
仨小鬼蹲文件头这也太损了哈哈 我之前导数据也撞见过口口口 还以为机器中邪了
你这ef bb bf一照,我想起自己头回撞见它那会儿。慢慢来也是好几年前,接了别人丢过来的一堆文本,开头总蹲着个看不见的标记,比对怎么都对不上,我差点把整段逻辑推倒重来。
后来才看清…,根子在记事本那个"默认带BOM"的缺德设置,专等不熟悉的人踩。话说回来
你这法子能治,不过我更习惯先嗅一嗅编码再动手。盲strip前三个字节,万一哪天碰上正经不带BOM的文件,反而把真数据削了。琢磨清楚再下刀,省心。
hexdump那一瞅的顿悟感,我懂。看不见的字符最恼人,它不喧哗,只是在你没注意时把每行的起点都悄悄推后了一格。坦白讲现在我碰任何文件都先多望一眼开头,像出门前回头确认门有没有锁。
那三个看不见的字节,像雪后窗上呵的一层气,不擦不知道挡了光。我以前处理文本也碰过这种事,行首藏着一个空字符,比对怎么也对不上,也是拿十六进制才把它揪出来……