最近在做数据处理时,遇到了一个让我抓狂的小问题。事情的经过是这样的:我用 Python 读取别人给的 CSV 文件 ,然后把数据写入数据库。按理来说,一切应该顺利进行,但当我拿着某个字段去做表关联时,发现很多数据都对不上。明明 字段值肉眼看起来是一样的,但 SQL 查询就是匹配不上。
这让我很疑惑,难道数据真的不一样?还是数据库出了问题?带着这些疑问,我开始了一场debug 大冒险。
问题发现:隐藏的"幽灵字符" {#问题发现隐藏的幽灵字符}
既然查询不匹配,那最直接的办法就是 print() 输出调试,看看数据库里存的值和 CSV 里读取的值到底有什么区别。于是,我把字段打印出来:
print(repr(field_value))
结果让我大吃一惊:
'\ufeffcustomer_id'
竟然多了个 \ufeff
?这是什么鬼?这时候我才意识到,原来字段的前面藏着一个看不见的"幽灵字符",它正是导致 SQL 关联失败的罪魁祸首。
为什么会出现 \ufeff
? {#为什么会出现-ufeff}
查了一圈资料后,我才明白,\ufeff
其实是 BOM(Byte Order Mark,字节顺序标记) ,一般出现在 UTF-8 带 BOM 的文本文件里。很多 Windows 上用 Excel 生成的 CSV 文件,默认都会加上 BOM,而 Python 直接读取时,并不会自动去掉它。于是,这个隐藏字符就被当成了数据的一部分,导致字段匹配失败。
简单来说,数据库里存的是「customer_id」 ,但 CSV 里读取的值其实是 「\ufeffcustomer_id」,这样一来,怎么可能匹配得上呢?
如何解决? {#如何解决}
方法 1:用 utf-8-sig
读取文件(推荐) {#方法-1用-utf-8-sig-读取文件推荐}
既然问题出在 文件编码 上,那最简单的办法就是在读取 CSV 时,使用 utf-8-sig
作为编码格式:
import csv
with` `open("data.csv",` `"r",` `encoding="utf-8-sig")` `as` `f:`
`reader` `=` `csv.reader(f)`
`for` `row` `in` `reader:`
`print(row)` `# \ufeff 自动去掉`
`
这一行代码直接解决了问题,\ufeff
再也不会出现在数据里。
方法 2:手动去掉 \ufeff
{#方法-2手动去掉-ufeff}
如果文件已经读取了,或者你不确定是不是所有文件都有 BOM,也可以手动去掉:
field_value = field_value.lstrip("\ufeff")
或者:
field_value = field_value.replace("\ufeff", "")
这两个方法适合 处理单个字段 ,如果已经导入数据库,发现有问题,可以批量执行 UPDATE
语句清理数据。
踩坑总结 {#踩坑总结}
这次的经历让我学到了一个道理:「看起来一样的数据,不一定真的一样!」
以后遇到类似的字段匹配问题,一定要:
- 多用
repr()
或ord()
检查数据,看看有没有隐藏字符。 - 优先使用
utf-8-sig
读取 CSV,防止 BOM 影响数据。 - 手动去掉
\ufeff
作为兜底方案,防止错误传播到数据库。
这个小问题虽然简单,但要是忽略了,可能会浪费很多时间去排查业务逻辑的错误。所以,以后看到 字段匹配不上的问题,第一步就该先看看数据是不是"长得像但其实不一样"!🚀