Excel 为什么会毁掉你的 CSV,以及如何阻止它
CSV 文件是文本。用 Excel 打开,它就不再是文本了,因为 Excel 一边读取每个字段,一边判断这个字段应该是什么,并据此改写它。多数时候猜对了,没人察觉。一旦猜错,损坏是无声的,保存的那一刻就无法挽回,而且往往会怪到发文件的人头上。
最先牺牲的是前导零
007 这个值在 Excel 看来,就是前面多了两个多余字符的数字 7,于是它真的变成 7。邮政编码、支行代码、零件编号,以及任何位数本身带有含义的标识符,都会遭遇同样的事。
这一类还算容易发现,因为那一列会明显变成右对齐,零也不见了。很多人会手工修补,在值前面加一个单引号——这能撑到下一次导出为止。
Excel 只保留十五位有效数字
真正造成损失的是这一条,因为它看上去毫无异样。在 Excel 中以数字形式保存的值,只保留十五位有效数字。粘贴一个十六位的订单参考号、一个很长的交易 ID,或者类似卡号的数字,最后一位就会变成零。
单元格里显示的仍是一长串数字,没有高亮,也没有警告。只是这个值已经不是你原来的值了,而基于它的所有匹配从此开始失败——查明原因往往要花掉一个下午。超过十五位的内容必须以文本形式保存,事后无论怎么改显示格式都无法恢复,因为写入磁盘的内容里,那些位数早已消失。
长得像日期的编码就会变成日期
输入 3-1,Excel 还给你 3 月 1 日。输入 SEPT1,你得到 9 月 1 日。这不是刻意编出来的例子:遗传学界曾大规模遭遇此事,因为 SEPT1、MARCH1、DEC1 这类基因符号,正好就是日期解析器要找的形状。
问题严重到 2020 年负责人类基因命名的委员会索性把受影响的符号改名,而不是继续跟表格软件争论下去。既然给基因改名反而是更省事的一条路,那也该假定你自己的产品编码并没有什么特别。
编码问题是另一回事,同样恼人
以 UTF-8 保存但不带字节顺序标记的 CSV,在 Excel 中会按系统的旧编码来解释,于是所有中文或带重音的字符都变成乱码。给同一个文件加上该标记,它就能干净地打开。
这就是为什么同一份导出,一位同事看到的是整齐的表格,另一位看到的却是乱码。文件在两人之间并没有变,只是两台机器猜了不同的编码。
连分隔符都不是固定的
Excel 并不总是按逗号切分。在小数点分隔符为逗号的地区,也就是欧洲的大部分地方,Excel 期望字段之间是分号,于是逗号分隔的文件会作为高高一整列文本被读进来。
文件并没有格式错误,只是被用与写入时不同的区域设定读取了。这与编码问题属于同一类,也会引出同一句抱怨:在我这儿是好的呀。
真正能杜绝这些的做法
别再双击打开 CSV 文件。改用数据选项卡下的导入路径,并在数据落进工作表之前,把每个脆弱的列都设为文本。那个导入对话框,是决定权属于你而不属于 Excel 的唯一时刻。
较新的版本也把这种猜测做成了设置项:依次进入选项和数据,可以分别关闭日期、长数字和前导零的自动转换。经常处理导出数据的机器,三项都值得关掉。
更持久的办法是:不要把 CSV 发给会用 Excel 打开它的人。在真正的 .xlsx 工作簿里,每个单元格都随身带着自己的类型,因此写成文本的列,无论谁在哪台机器、用什么区域设置打开,都仍然是文本。
检查已经过 Excel 的文件
文件一旦从 Excel 保存过,损坏就存在于保存下来的值里,而不在显示上,所以把列拉宽什么也证明不了。请留意比应有长度更短的标识符、结尾是可疑整零的长数字,以及编码列中悄悄变成日期的内容。
最快的检查方式,是把原始文件当作纯文本而不是表格打开,拿几个已知的值与表格显示的对照。若对不上,那份表格就不是你数据的一个视图,而是另一套数据——值得留下的是那个文本文件。