utf-8 utf-8-sig区别

推荐词

用pandas处理数据保存csv时,utf-8也乱码,copilot推荐使用utf-8-sig,好了

每天一个编码小bug​:sweat_smile:

正文

本文由 简悦 SimpRead 转码, 原文地址 www.cnblogs.com

前言:在写入 csv 文件中,出现了乱码的问题。

解决:utf-8 改为 utf-8-sig

区别如下:

1、”utf-8“ 是以字节为编码单元, 它的字节顺序在所有系统中都是一样的, 没有字节序问题, 因此它不需要 BOM, 所以当用 “utf-8” 编码方式读取带有 BOM 的文件时, 它会把 BOM 当做是文件内容来处理, 也就会发生类似上边的错误.

2、“uft-8-sig"中 sig 全拼为 signature 也就是" 带有签名的 utf-8”, 因此 “utf-8-sig” 读取带有 BOM 的 “utf-8 文件时” 会把 BOM 单独处理, 与文本内容隔离开, 也是我们期望的结果.

with open('data.csv', 'w',encoding='utf_8_sig') as fp:

utf-8 保存的 csv 格式文件要让 Excel 正常打开的话,需要在文件最前面加入 BOM(Byte order mark)。如果接收者收到以 EF BB BF 开头的字节流,就知道这是 UTF-8 编码了。

所以在 write 文件的内容数据之前,先 write 一下 BOM。如下面代码

FileOutputStream fos = new FileOutputStream(new File(this.csvFileAbsolutePath));

    byte [] bs = { (byte)0xEF, (byte)0xBB, (byte)0xBF};  //UTF-8 编码

    fos.write(bs); 

    fos.write(...);

    fos.close(); 

这样添加了 BOM 的 CSV 文件用 excel 直接打开,是不会出现乱码的。

我当时遇到的问题是这样的。下载 CSV 文件,用 excel 打开,中文乱码,用 atom,notepad++ 和 记事本打开,显示正常。 查资料发现是 excel 不能识别无 BOM 头的 unicode 文件问题,就是 excel 在打开 CSV 文件时默认用 ASNI 打开。 所以需要添加 BOM 头。

BOM 的含义

BOM 即 Byte Order Mark 字节序标记。BOM 是为 UTF-16 和 UTF-32 准备的,用户标记字节序(byte order)。拿 UTF-16 来举例,其是以两个字节为编码单元,在解释一个 UTF-16 文本前,首先要弄清楚每个编码单元的字节序。例如收到一个 “奎” 的 Unicode 编码是 594E,“乙”的 Unicode 编码是 4E59。如果我们收到 UTF-16 字节流 “594E”,那么这是 “奎” 还是“乙”?

Unicode 规范中推荐的标记字节顺序的方法是 BOM:在 UCS 编码中有一个叫做 **“ZERO WIDTH NO-BREAK SPACE”(零宽度无间断空间)**的字符,它的编码是 FEFF。而 FEFF 在 UCS 中是不不能再的字符(即不可见),所以不应该出现在实际传输中。UCS 规范建议我们在传输字节流前,先传输字符 “ZERO WIDTH NO-BREAK SPACE”。这样如果接收者接收到 FEFF,就表明这个字节流是 Big-Endian 的;如果收到 FFFE,就表明这个字节流是 Little-Endian 的。因此字符 “ZERO WIDTH NO-BREAK SPACE” 又被称为 BOM。

UTF-8 是以字节为编码单元,没有字节序的问题


延伸一下:

UTF-8 编码是以 1 个字节为单位进行处理的,不会受 CPU 大小端的影响;需要考虑下一位时就地址 + 1。

UTF-16、UTF-32 是以 2 个字节和 4 个字节为单位进行处理的,即 1 次读取 2 个字节或 4 个字节,这样一来,在存储和网络传输时就要考虑 1 个单位内 2 个字节或 4 个字节之间顺序的问题。


UTF-8 BOM

UTF-8 BOM 又叫 UTF-8 签名,UTF-8 不需要 BOM 来表明字节顺序,但可以用 BOM 来表明编码方式。当文本程序读取到以 EF BB BF 开头的字节流时,就知道这是 UTF-8 编码了。Windows 就是使用 BOM 来标记文本文件的编码方式的


补充:

“ZERO WIDTH NO-BREAK SPACE” 字符的 UCS 编码为 FEFF(假设为大端),对应的 UTF-8 编码为 EF BB BF


即以 EF BB BF 开头的字节流可表明这是段 UTF-8 编码的字节流。但如果文件本身就是 UTF-8 编码的,EF BB BF 这三个字节就毫无用处了。 所以,可以说 BOM 的存在对于 UTF-8 本身没有任何作用

UTF-8 文件中包含 BOM 的坏处

1、对 php 的影响

php 在设计时就没有考虑 BOM 的问题,也就是说他不会忽略 UTF-8 编码的文件开头的那三个 EF BB BF 字符,直接当做文本进行解析,导致解析错误。

2、在 linux 上执行 SQL 脚本报错


最近开发过程中遇到,windows 下编写的 SQL 文件,在 linux 下执行时,总是报错。

在文件的开头,无论是使用中文注释还是英文注释,甚至去掉注释,也会报 SP2-0734: unknown command beginning “?<span”=“”>dec<span"=“”>lare …" - rest of line ignored. 的错误。
<span “=”"> 如下是文件开头部分

1 --create tablespace
2 declare
3 v_tbs_name varchar2(200):='hytpdtsmsshistorydb';
4 begin

报错如下:

1 SP2-0734: unknown command beginning "?--create ..." - rest of line ignored.
4 PL/SQL procedure successfully completed.

网上没有找到类似问题的解决办法,且文件编码确认已经更改为 utf-8,该问题困惑了我很久。
最后查看一下 BOM 与 no BOM 的区别,尝试更改为 no BOM,居然就没有再出现错误。

修改完成后,无论使用中文,还是英文,或者去掉注释,都能正常执行。


血泪建议:UTF-8 最好不要带 BOM

UTF-8」和「带 BOM 的 UTF-8」的区别就是有没有 BOM。即文件开头有没有 U+FEFF。

1、Linux 中查看 BOM 的方法:使用 less 命令,其它命令可能看不到效果:

发现词语之前多了一个 <U+FEFF>。

2、UTF-8 去除 BOM 的方法

Linux 下:

(1)

1)vim 打开文件

2) 执行: set nobomb

3) 保存: wq

(2)

dos2unix filename

将 windows 格式文件转为 Unix、Linux 格式文件。该命令不仅可将 windows 文件的换行符 \ r\n 转为 Unix、Linux 文件的换行符 \ n,还可以将 UTF-8 Unicode (with BOM) 转换为 UTF-8 Unicode.

PS:

遇到一个比较坑爹的情况,1 个 UTF-8 Unicode (with BOM) 文件中包含两个 < U+FEFF>,这是无论使用方法(1)还是方法(2),都要执行两次才能将 < U+FEFF > 完全去除!!!

(2)Windows 下,使用 NotePad++ 打开这个文件,然后选择 “编码”,再选择 “以 UTF-8 无 BOM 格式编码”,最后重新保存文件即可!

参考资料来源:python 字符串编码 ,区别 utf-8 和utf-8-sig - 静悟生慧 - 博客园

相关内容