Python学习 如何将UTF-8编码转换成UTF-8 BOM编码?

Posted 欧阳鹏

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python学习 如何将UTF-8编码转换成UTF-8 BOM编码?相关的知识,希望对你有一定的参考价值。

一、需求描述

在我之前的博客:
【我的Android进阶之旅】使用TextAnalysisTool来快速提高你分析文本日志的效率
中有介绍下面一个关于中文无法显示的问题,如下所示:


有时候,中文无法正常显示,如下所示都是乱码

在这里插入图片描述
这个时候,我们需要借助下 NotePad++ 工具,对整个日志文件进行转码,如下所示

我们发现,此文件用NotePad++ 打开,可以直接显示中文,
编码格式为 UTF-8编码

在这里插入图片描述

我们使用快捷键 Ctrl+A 全选日志内容,选择【编码】–>【使用 UTF-8 BOM编码】,将日志内容切换编码,然后保存。

在这里插入图片描述

现在我们切换了编码为【UTF-8 BOM】之后,重新用TextAnalysisTool工具打开这份日志就可以正常显示中文了

在这里插入图片描述


上面的方法,我们通过使用NotePad++ 工具,来对整个日志文件进行转码。然后再进行查看,这样的步骤有点繁琐。有时候需要分析多份日志的时候就会显得很恶心。

所以在想,有没有其他的方式将utf-8编码转成utf-8 BOM编码呢?

二、实现需求:将UTF-8编码转成UTF-8 BOM编码

我们可以使用python来实现这个需求。

2.1 了解下UTF-8 and UTF-8 BOM(Byte Order Mark)的区别

大家可以通过以下几个链接了解一下UTF-8 and UTF-8 BOM(Byte Order Mark)的区别。

结论:

UTF-8 不需要 BOM,尽管 Unicode 标准允许在 UTF-8 中使用 BOM。
所以不含 BOM 的 UTF-8 才是标准形式,在 UTF-8 文件中放置 BOM 主要是微软的习惯(顺便提一下:把带有 BOM 的小端序 UTF-16 称作「Unicode」而又不详细说明,这也是微软的习惯)。

什么是BOM

BOM(byte-order mark),即字节顺序标记,它是插入到以UTF-8、UTF16或UTF-32编码Unicode文件开头的特殊标记,用来识别Unicode文件的编码类型。

对于UTF-8来说,BOM并不是必须的,因为BOM用来标记多字节编码文件的编码类型和字节顺序(big-endian或little-endian)。

在绝大多数编辑器中都看不到BOM字符,因为它们能理解Unicode,去掉了读取器看不到的题头信息。若要查看某个Unicode文件是否以BOM开头,可以使用十六进制编辑器。下表列出了不同编码所对应的BOM。

BOM Encoding
EF BB BF UTF-8
FE FF UTF-16 (big-endian)
FF FE UTF-16 (little-endian)
00 00 FE FF UTF-32 (big-endian)
FF FE 00 00 UTF-32 (little-endian)

UTF-8以字节为编码单元因此不需要 BOM 来表明字节顺序,但可以用 BOM 来表明编码方式。字符 “Zero Width No-Break Space” 的 UTF-8 编码是 EF BB BF。所以如果接收者收到以 EF BB BF 开头的字节流,就知道这是 UTF-8编码了。

在这里插入图片描述

因此UTF-8编码的字符串开头处的三个bytes 0xef,0xbb,0xbf就称为UTF-8 BOM头。

BOM的来历

为了识别 Unicode 文件,Microsoft 建议所有的 Unicode 文件应该以 ZERO WIDTH NOBREAK SPACE(U+FEFF)字符开头。这作为一个“特征符”或“字节顺序标记(byte-order mark,BOM)”来识别文件中使用的编码和字节顺序。

Linux/UNIX 并没有使用 BOM,因为它会破坏现有的 ASCII 文件的语法约定。

带BOM和不带BOM的区别

「UTF-8」和「带 BOM 的 UTF-8」的区别就是有没有 BOM。即文件开头有没有 U+FEFF,也就是说有没有这个标记。

在这里插入图片描述
但内容都一样 ,为什么相差了3个字节呢 ? 如下图 。

在这里插入图片描述
多出来的 ef bb bf 就是上面相差三个字节的原因 。

BOM——Byte Order Mark,就是字节序标记

bom是为utf-16和utf-32准备的,用于标记字节顺序。微软在utf-8中使用bom是因为这样可以把UTF-8和ASCII等编码区分开来,但这样的文件在windows之外的操作系统里会带来问题。

带还是不带?

如果你的编程平台需要跨平台编译,比如,会在linux平台上编译,而不是只在windows上运行,建议不带BOM,unicode标准就是不带,带BOM毕竟那是微软的那一套,带了会出现很大的问题。反之,如果你的程序只在windows平台上编译出windows程序,这个可有可无。
注意:这里所说的带还是不带,指的是:源码字符集(the source character set)-源码文件是使用何种编码保存的;

现在linux平台下的GCC 4.6及以上的版本已经可以支持带BOM的源码了!!!!!
所以之前出现的问题也可以不用冲突,带或者不带,以后就不会成为一个问题。

2.2 实现需求

参考链接: 【Adding BOM (unicode signature) while saving file in python】

import codecs
# https://stackoverflow.com/questions/5202648/adding-bom-unicode-signature-while-saving-file-in-python


""" 给指定文件,添加BOM标记
    参数:
        file: 文件
        bom: BOM标记
"""
def add_bom(file, bom: bytes):
    with open(file, 'r+b') as f:
        org_contents = f.read()
        f.seek(0)
        f.write(bom + org_contents)

# 定义一个测试文件,名为test.log
file = 'test.log'

# 打开 测试文件,使用utf-8编码写入一段中英文混杂的内容
with open(file, 'w', encoding='utf-8') as f:  # without BOM
    f.write('欧阳鹏 博客地址:https://blog.csdn.net/ouyang_peng')

# 加入BOM标记
#add_bom(file, codecs.BOM_UTF8)

# 打开测试文件,打印文件内容
with open(file, 'rb') as f:
    print(f.read())

在这里插入图片描述

总共有4个区域:

  • 区域1
    定义 add_bom方法,给指定文件,添加BOM标记
  • 区域2
    定义一个测试文件,名为test.log,打开 测试文件,使用utf-8编码写入一段中英文混杂的内容
  • 区域3
    给测试文件,加入BOM标记
  • 区域4
    打印测试文件的内容

2.2.1 测试写入utf-8内容并读取打印

import codecs
# https://stackoverflow.com/questions/5202648/adding-bom-unicode-signature-while-saving-file-in-python


""" 给指定文件,添加BOM标记
    参数:
        file: 文件
        bom: BOM标记
"""
def add_bom(file, bom: bytes):
    with open(file, 'r+b') as f:
        org_contents = f.read()
        f.seek(0)
        f.write(bom + org_contents)

# 定义一个测试文件,名为test.log
file = 'test.log'

# 打开 测试文件,使用utf-8编码写入一段中英文混杂的内容
with open(file, 'w', encoding='utf-8') as f:  # without BOM
    f.write('欧阳鹏 博客地址:https://blog.csdn.net/ouyang_peng')

# 加入BOM标记
#add_bom(file, codecs.BOM_UTF8)

# 打开测试文件,打印文件内容
with open(file, 'rb') as f:
    print(f.read())

运行程序,如下所示:

[Running] python -u "c:\\Users\\000\\Desktop\\add_utf8_bom.py"
b'\\xe6\\xac\\xa7\\xe9\\x98\\xb3\\xe9\\xb9\\x8f \\xe5\\x8d\\x9a\\xe5\\xae\\xa2\\xe5\\x9c\\xb0\\xe5\\x9d\\x80\\xef\\xbc\\x9ahttps://blog.csdn.net/ouyang_peng'

[Done] exited with code=0 in 1.038 seconds

在这里插入图片描述

使用 TextAnalysisTool 工具打开,乱码
在这里插入图片描述

2.2.2 测试写入utf-8内容,并给文件加入BOM标记,然后读取打印

import codecs
# https://stackoverflow.com/questions/5202648/adding-bom-unicode-signature-while-saving-file-in-python


""" 给指定文件,添加BOM标记
    参数:
        file: 文件
        bom: BOM标记
"""
def add_bom(file, bom: bytes):
    with open(file, 'r+b') as f:
        org_contents = f.read()
        f.seek(0)
        f.write(bom + org_contents)

# 定义一个测试文件,名为test.log
file = 'test.log'

# 打开 测试文件,使用utf-8编码写入一段中英文混杂的内容
with open(file, 'w', encoding='utf-8') as f:  # without BOM
    f.write('欧阳鹏 博客地址:https://blog.csdn.net/ouyang_peng')

# 加入BOM标记
add_bom(file, codecs.BOM_UTF8)

# 打开测试文件,打印文件内容
with open(file, 'rb') as f:
    print(f.read())

输出内容为:

[Running] python -u "c:\\Users\\000\\Desktop\\add_utf8_bom.py"
b'\\xef\\xbb\\xbf\\xe6\\xac\\xa7\\xe9\\x98\\xb3\\xe9\\xb9\\x8f \\xe5\\x8d\\x9a\\xe5\\xae\\xa2\\xe5\\x9c\\xb0\\xe5\\x9d\\x80\\xef\\xbc\\x9ahttps://blog.csdn.net/ouyang_peng'

[Done] exited with code=0 in 1.043 seconds

在这里插入图片描述
使用 TextAnalysisTool 工具打开,不会乱码了!
在这里插入图片描述

2.2.2 对比输出内容

[Running] python -u "c:\\Users\\000\\Desktop\\add_utf8_bom.py"
b'\\xe6\\xac\\xa7\\xe9\\x98\\xb3\\xe9\\xb9\\x8f \\xe5\\x8d\\x9a\\xe5\\xae\\xa2\\xe5\\x9c\\xb0\\xe5\\x9d\\x80\\xef\\xbc\\x9ahttps://blog.csdn.net/ouyang_peng'

[Done] exited with code=0 in 1.038 seconds

[Running] python -u "c:\\Users\\000\\Desktop\\add_utf8_bom.py"
b'\\xef\\xbb\\xbf\\xe6\\xac\\xa7\\xe9\\x98\\xb3\\xe9\\xb9\\x8f \\xe5\\x8d\\x9a\\xe5\\xae\\xa2\\xe5\\x9c\\xb0\\xe5\\x9d\\x80\\xef\\xbc\\x9ahttps://blog.csdn.net/ouyang_peng'

[Done] exited with code=0 in 1.043 seconds

在这里插入图片描述

对比 UTF-8 和 UTF-8 BOM的内容,可以发现,多了\\xef\\xbb\\xbf三个字节,因此UTF-8编码的字符串开头处的三个bytes 0xef,0xbb,0xbf就称为UTF-8 BOM头。

三、扩展

3.1 扩展为可实际使用的脚本

上面的demo我们测试完毕之后,我们扩展一下,使之扩展为可实际使用的脚本。

add_utf8_bom.py 的代码如下,

import sys
import os
import glob
import codecs

""" 给指定文件,添加BOM标记
    参数:
        file: 文件
        bom: BOM标记
"""
def add_bom(file, bom: bytes):
    print("now,add_bom for file :[%s] ,with bom:[%s]" %(file,bom))
    with open(file, 'r+b') as f:
        org_contents = f.read()
        f.seek(0)
        f.write(bom + org_contents)

""" 根据给定的不同参数,给指定文件,添加BOM标记
    参数:
      args  传入进来的参数。
      
      如果参数只有一个,则区分是目录还是文件,
            如果是文件夹,则遍历文件夹中的.log日志文件,然后给每个.log日志文件添加BOM标记
            如果是文件则直接添加BOM标记。
      
      如果不传参数,则直接遍历当前目前下的所有.log日志文件  
"""
def main(args):
    if 1 == len(args):
        if os.path.isdir(args[0]):
            filelist = glob.glob(args[0] + "/*.log")
            for filepath in filelist:
                add_bom(filepath, codecs.BOM_UTF8)
        else:
            add_bom(args[0], codecs.BOM_UTF8)
    else:
        filelist = glob.glob("*.log")
        for filepath in filelist:
            add_bom(filepath, codecs.BOM_UTF8)

if __name__ == "__main__":
    main(sys.argv[1:])

我们来做一下测试,我们准备一个目录 C:\\Users\\000\\Desktop\\test_bom,放好写好的脚本,以及4个utf-8格式的文件,如下所示:

在这里插入图片描述
文件打开是乱码的

在这里插入图片描述

3.1.1 传入一个指定文件路径

如下所示:指定传入一个指定的文件名。文件名可以传入相对路径或者绝对路径。

  • 相对路径
PS C:\\Users\\000> cd "c:\\Users\\000\\Desktop\\test_bom"
PS C:\\Users\\000\\Desktop\\test_bom> python -u "c:\\Users\\000\\Desktop\\test_bom\\add_utf8_bom.py" "test_utf-8.log"
now,add_bom for file :[test_utf-8.log] ,with bom:[b'\\xef\\xbb\\xbf']
PS C:\\Users\\000\\Desktop\\test_bom> 

在这里插入图片描述

  • 绝对路径
PS C:\\Users\\000\\Desktop\\test_bom> python -u "c:\\Users\\000\\Desktop\\test_bom\\add_utf8_bom.py" "C:\\Users\\000\\Desktop\\test_bom\\test_utf-8.log" 
now,add_bom for file :[C:\\Users\\000\\Desktop\\test_bom\\test_utf-8.log] ,with bom:[b'\\xef\\xbb\\xbf']
PS C:\\Users\\000\\Desktop\\test_bom>

在这里插入图片描述
两种方式都可以识别,然后可以看到日志打印,添加了BOM标记头。

我们可以看到C:\\Users\\000\\Desktop\\test_bom\\test_utf-8.log的时间和其他的文件不同,以被修改。
在这里插入图片描述
打开文件内容查看,不乱码!
在这里插入图片描述

3.1.2 传入一个指定文件夹路径

传入一个指定文件夹路径,如下所示,传入文件夹路径为:C:\\Users\\000\\Desktop\\test_bom\\

PS C:\\Users\\000\\Desktop\\test_bom> python -u "c:\\Users\\000\\Desktop\\test_bom\\add_utf8_bom.py" "C:\\Users\\000\\Desktop\\test_bom\\"
now,add_bom for file :[C:\\Users\\000\\Desktop\\test_bom\\test_utf-8  (1).log] ,with bom:[b'\\xef\\xbb\\xbf']
now,add_bom for file :[C:\\Users\\000\\Desktop\\test_bom\\test_utf-8  (2).log] ,with bom:[b'\\xef\\xbb\\xbf']
now,add_bom for file :[C:\\Users\\000\\Desktop\\test_bom\\test_utf-8  (3).log] ,with bom:[b'\\xef\\xbb\\xbf']
now,add_bom for file :[C:\\Users\\000\\Desktop\\test_bom\\test_utf-8.log] ,with bom:[b'\\xef\\xbb\\xbf']
PS C:\\Users\\000\\Desktop\\test_bom>

在这里插入图片描述

我们可以看到该文件夹下所有的log日志文件都被修改。

打开该文件夹下所有的log日志文件,查看下内容不乱码!
在这里插入图片描述

3.1.3 不传入指定路径

不传入指定路径,则会遍历当前路径下所有的.log日志文件。

PS C:\\Users\\000\\Desktop\\test_bom> python -u "c:\\Users\\000\\Desktop\\test_bom\\add_utf8_bom.py"
now,add_bom for file :[test_utf-8  (1).log] ,with bom:[b'\\xef\\xbb\\xbf']
now,add_bom for file :[test_utf-8  (2).log] ,with bom:[b'\\xef\\xbb\\xbf']
now,add_bom for file :[test_utf-8  (3).log] ,with bom:[b'\\xef\\xbb\\xbf']
now,add_bom for file :[test_utf-8.log] ,with bom:[b'\\xef\\xbb\\xbf']
PS C:\\Users\\000\\Desktop\\test_bom>

在这里插入图片描述
和传入指定文件夹路径的效果类似。

3.2 将Python脚本加入Windows右键菜单

写一个工具直接鼠标右键一键可以转换UTF-8编码转换成UTF-8 BOM编码,方便我在windows电脑上使用TextAnalysisTool工具来分析日志。

具体可以参考下面这个操作

我们来看实际效果。

3.2.1 先写一个批处理文件

现在我们将这个命令封装成一个bat文件,这样我们以后就可以直接运行bat文件即可,不需要每次都敲命令了。

比如我们封装为 add_utf_bom.bat 文件,放在C:\\Windows目录下,内容如下

在这里插入图片描述

add_utf_bom.bat 文件源代码如下:

C:\\Python39\\python.exe C:\\Windows\\add_utf8_bom.py %*

  • 第一个参数 C:\\Python39\\python.exe 表示要运行的python程序的路径,上面的python.exe文件在c:\\Python39目录下,如下所示
    在这里插入图片描述

如果你的python文件不是这个目录,改为你自己的python安装目录。

  • 第二个参数 C:\\Windows\\add_utf8_bom.py 表示添加BOM标记的python脚本路径

3.2.2 先写一个注册表文件

在这里插入图片描述

add_utf_bom.reg文件的内容为:

Windows Registry Editor Version 5.00
[HKEY_CLASSES_ROOT\\*\\shell\\add_utf_bom\\command]
@="add_utf_bom.bat \\"%1\\""

然后双击该注册表,即可导入注册表。

在这里插入图片描述
点击 【是(Y)】,即可导入成功!

在这里插入图片描述
导入注册表成功之后,查询下注册表内容,如下所示:

在这里插入图片描述

3.2.3 测试鼠标右键add_utf_bom菜单

在这里插入图片描述
一闪而过,执行成功
在这里插入图片描述

在这里插入图片描述

OK,整个需求完整实现,可以对指定的utf-8编码的文件,先使用鼠标右键菜单【add_utf_bom】实现添加BOM头的功能,然后再使用TextAnalysisTool工具来查看不乱码的日志文件!

四、再次扩展功能:添加完BOM头之后,直接用TextAnalysisTool工具打开此文件

4.1 待优化的现状

上面的步骤做完之后,我们可以很方便的给文件进行转码,给UTF-8格式的文件加上BOM头,使之可以使用TextAnalysisTool工具打开此文件后不乱码。
但是这样得进行两步骤

  1. 鼠标右键: 选择我们弄好的【add_utf_bom】菜单项,进行编码转换

在这里插入图片描述
2. 重新打开此文件
在这里插入图片描述
略显麻烦,因此我想把两个步骤合并为一个,当点击鼠标右键: 选择我们弄好的【add_utf_bom】菜单项,进行编码转换之后,直接使用TextAnalysisTool工具打开此文件。

4.2 实现功能

因此我们修改下python脚本即可。

import sys
import os
import glob
import codecs

""" 给指定文件,添加BOM标记
    参数:
        file: 文件
        bom: BOM标记
"""
def add_bom(file, bom: bytes):
    print("now,add_bom for file :[%s] ,with bom:[%s]" %(file,bom))
    with open(file, 'r+b') as f:
        org_contents = f.read()
        f.seek(0)
        f.write(bom + org_contents)

""" 根据给定的不同参数,给指定文件,添加BOM标记
    参数:
      args  传入进来的参数。
      
      如果参数只有一个,则区分是目录还是文件,
            如果是文件夹,则遍历文件夹中的.log日志文件,然后给每个.log日志文件添加BOM标记
            如果是文件则直接添加BOM标记。
      
      如果不传参数,则直接遍历当前目前下的所有.log日志文件  
"""
def main(args):
    if 1 == len(args):
        if os.path.isdir(args[0]):
            filelist = glob.glob(args[0] + "/*.log")
            for filepath in filelist:
                add_bom(filepath, codecs.BOM_UTF8)
        else:
            add_bom(args[0], codecs.BOM_UTF8)
            # 如果是单独打开某个文件,肯定是鼠标右键进来的,或者直接指定要打开这个文件的
            # 那么加上BOM标记之后,直接使用TextAnalysisTool工具直接打开
            # TextAnalysisTool 工具安装的路径为: D:\\TextAnalysisTool.NET\\TextAnalysisTool.NET.exe
            # 所以直接打开此文件
            # TextAnalysisTool 安装目录为: D:\\TextAnalysisTool.NET
            # TextAnalysisTool 程序名为: TextAnalysisTool.NET.exe
            # 要打开的文件为: args[0] 传进来的参数
            os.system('start "" /d "D:\\TextAnalysisTool.NET" /wait "TextAnalysisTool.NET.exe" %s' %args[0])
    else:
        filelist = glob.glob("*.log")
        for filepath in filelist:
            add_bom(filepath, codecs.BOM_UTF8)

if __name__ == "__main__":
    main(sys.argv[1:])

添加了标红的一段代码
在这里插入图片描述
TextAnalysisTool 工具安装的路径为: D:\\TextAnalysisTool.NET\\TextAnalysisTool.NET.exe
在这里插入图片描述
添加的部分代码如下所示:

# 如果是单独打开某个文件,肯定是鼠标右键进来的,或者直接指定要打开这个文件的
            # 那么加上BOM标记之后,直接使用TextAnalysisTool工具直接打开
            # TextAnalysisTool 工具安装的路径为: D:\\TextAnalysisTool.NET\\TextAnalysisTool.NET.exe
            # 所以直接打开此文件
            # TextAnalysisTool 安装目录为: D:\\TextAnalysisTool.NET
            # TextAnalysisTool 程序名为: TextAnalysisTool.NET.exe
            # 要打开的文件为: args[0] 传进来的参数
            os.system('start "" /d "D:\\TextAnalysisTool.NET" /wait "TextAnalysisTool.NET.exe" %s' %args[0])

4.3 测试一键转码并打开功能

在这里插入图片描述
转码中
在这里插入图片描述
自动打开转码后的文件
在这里插入图片描述
恩,到此为止,这个工具用起来才得心应手!

五、参考链接

以上是关于Python学习 如何将UTF-8编码转换成UTF-8 BOM编码?的主要内容,如果未能解决你的问题,请参考以下文章

如何将gbk 编码的字符串转换成 utf

utf-8字符串转成中文如何转换

python---字符编码

Python判断字符串中是不是有中文字符

python中把ISO-8859-1编码转化为UTF-8

utf-8编码的页面如何转成gbk编码的页面(急)