从*.csv乱码了解unicode

955 阅读2分钟

发现问题

在MacOS开发时,导出_.csv文件时,在WPS打开时正常,但是在Office Excel打开会乱码,可使用如下代码模拟_.csv文件下载

const a = document.createElement('a');
a.href = 'data:text/csv,学号,语文,数学,物理\n10,20,30,40\n50,60,70,80';
a.download = 'test.csv';
a.innerText = '点击我下载';
document.body.append(a);

寻找原因

经过Google所得

  1. Office Excel在读取*.csv文件时,是通过读取该文件的BOM来识别编码,如果该文件不存在BOM,则会按照默认编码解读,会出现乱码
  2. 在上述步骤导出CSV时,未在头部添加BOM

许多视窗程序(包含记事本)会需要添加字节顺序标记到UTF-8文件,否则将无法正确解析编码,而出现乱码。

由以上原因,导致了Office Excel 读取该文件时编码不一致,从而导致了乱码

解决

既然是由于BOM导致的问题,那么加上BOM就好了

const a = document.createElement('a');
a.href = 'data:text/csv,\uFEFF学号,语文,数学,物理\n10,20,30,40\n50,60,70,80';
a.download = 'test.csv';
a.innerText = '点击我下载';
document.body.append(a);

BOM

什么是BOM

BOM:此BOM非彼BOM,这里的BOM不是指浏览器对象模型,而是指的是 Byte Order Mark(字节序)

大端序和小端序

BOM分为两个顺序,大端序、小端序,下面拿一个例子来解释,"我"的码点为 25105,转为16进制为 0x6211

大端序:高位字节在前,0x62在前,0x11在后,比较符合人类识别,例如阿拉伯数字100,我们习惯高位在前

小端序:高位字节在后,0x11在前,0x62在后

计算机在读取数据的时候,是按照一个字节一个字节读取,假设存储顺序为 [0x62, 0x11],此时如果计算机按照大端序解析,则得到 "我",反之得得到 "ᅢ"

以下是常用的BOM

编码BOM表示
UTF-8EF BB BF
UTF-16(大端序)FE FF
UTF-16(小端序)FF FE
UTF-32(大端序)00 00 FE FF
UTF-32(小端序)FF FE 00 00

为什么UTF-8不需要指出BOM

UTF-16需要两个字节存储,上文说道计算机是按照一个字节读取的,必然得要知道字节序,那为什么UTF-8不需要呢?这是由于UTF-8的存储方式有关

UTF-8存储为1-4个字节,那么它怎么知道到底这个字符占了几个字节?UTF-8使用第一字节前几位表示整个字节的长度,如下所示

1字节:0xxx xxxx
2字节:110x xxxx 10xx xxxx
3字节:1110 xxxx 10xx xxxx 10xx xxxx
4字节:1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx

所以对于UTF-8来说,它的字节顺序已经定死了