跳到主要内容
PulsarKit

导入CSV前,先清理Windows-1251编码和BOM问题

在电子表格里打开完全正常的CSV导出文件,仍可能因为一个看不见的字符或错误的编码,让JSON导入出问题。

作者:PulsarKit · ·

文件看起来完全正常,编码却可能不对

从老旧的财务软件或数据库软件导出的CSV文件,很多时候根本不是UTF-8。西里尔文字用的Windows-1251,西欧带重音字符用的Windows-1252,至今仍是多年前搭建的系统常见的输出编码。电子表格软件打开这类文件时往往不会报错,因为它会自动套用自己猜测的编码。所以文件一直看起来很正常,直到被不那么宽容的程序读取:脚本、导入流程或数据库加载工具默认按UTF-8读取,读出来的不是原来的文字,而是满屏乱码。

文件开头三个字节的标记,就能让严格的解析器出错

UTF-8字节顺序标记(BOM)是一个看不见的标记,只有三个字节,位于文件最开头,表示后面的文字是Unicode。对Excel这类会检查它的程序来说,它很有用。可一旦目标是严格的JSON导入程序,或者没有预料到它的脚本,它就成了问题。这几个多出来的字节会粘在第一列表头的第一个字符上,于是本该读作“id”的列,在其余代码按这个名字查找它的地方都对不上了。在转换前检测并去掉这个标记,而不是把它留在结果文件里,就能避免一种事后很难查清的不匹配。

自动识别正确的编码,不用从菜单里挑选

可靠的编码检测,也就是CSV转JSON在读取第一行之前就会做的检测,先检查有没有字节顺序标记,再尝试把其余字节严格按UTF-8校验;只有严格校验失败时,才根据高位字节的分布,回退到Windows-1251或Windows-1252。这个顺序很重要。本来就是UTF-8的文件,绝不会因为多疑而被误读成别的编码;不是UTF-8的文件则能被正确识别,而不是硬按UTF-8读取,一路变成乱码。CSV转Excel前面也有同样的检测,用于目标是电子表格而不是脚本的情况。

数据类型和字符编码同样重要

字符编码弄对了,只解决了CSV转JSON时出问题的一半。另一半是决定哪些值应该变成JSON的数字或布尔值,哪些应该保留为普通文本。像00123这样的值一旦转成数字123,前导零就永远丢了;超过大约十五位的标识符,一旦变成标准浮点数而不是保留为文本,马上就会被四舍五入。这两种值都应该保留为字符串,因为转换改变的是数据本身,而不只是格式或外观。

重复的表头搞坏导入的方式,和编码错误不一样

JSON对象里不能有两个同名的键。所以如果源文件里有两列碰巧用了同一个表头名称(由多个源系统拼起来的导出文件里,这并不少见),转换时就需要把重复的列改成不同的名字。否则,在每个结果对象里,第二列的数据都会覆盖第一列,而且没有任何提示。这和编码、类型问题是两种不同的故障,但同样可能悄悄损坏一次导入。值得确认转换工具在发生这种情况时会报告出来,而不是不声不响地解决冲突;把结果交给JSON格式化,改过名的键一眼就能看到。

分步操作:导入前先检查文件

先在CSV转JSON里把导出文件转换一次,分隔符和编码都保持自动,然后检查这两个猜测:把结果发送到JSON格式化(页面给出的下一步之一),读一读前几条记录。西里尔字母变成乱码或重音字符损坏,说明编码猜错了;如果只有一个很长的键,里面还夹着分隔符,说明分隔符猜错了。手动设置猜错的那一项,再转换一次:编码菜单提供Windows-1251、Windows-1252、带BOM或不带BOM的UTF-8以及UTF-16 LE,分隔符菜单提供逗号、分号、制表符、竖线或自定义字符。如果文件的分隔符或编码完全无法识别,工具会给出提示并拒绝转换,而不是转出一堆无意义的内容。

接着决定值的类型:默认设置已经把带前导零的值和长标识符保留为文本;如果文件全是代码、电话号码或账户编号,把“值类型”设为“全部保留为文本”,就什么都不会转换。结果还在JSON格式化里打开时,找一找源文件混乱留下的两个痕迹:两列表头都是id时,输出为id和id_2;某一行的字段比表头多时,多出来的部分放在__extra键下。这两种问题在源文件里修复,都比在日后会被它们卡住的系统里修复省事。一批最多二十个文件、总共300 MB,全程不离开浏览器标签页。

本文用到的工具

继续阅读