【Python】ASCII、UTF-8、GB2312 编码方式如何解决?
问题描述
使用 Python 处理文本文件时,遇到以下问题:
- 不知道编码方式
- 批量处理时包含不同的编码方式
对于问题 1,可以通过一些文本编辑器确定,再指定编码方式,但这样觉得麻烦;对于问题 2,不指定编码方式或指定某种方式都可能导致文件打开失败或是乱码问题。
解决方法
目前我使用的方法是使用 chardet
库先检测一下编码方式,再使用对应的编码方式打开。 chardet
库的安装在此不介绍。代码如下:
import chardet
def detect_encoding(file_path):
# 先按二进制方式读取
with open(file_path, 'rb') as f:
contents = f.read()
result = chardet.detect(contents) # chardet.detect() 返回一个字典
return result['encoding']
chardet.detect() 介绍
该函数的参数为 bytes 类型的数据,即二进制数据字节流。它利用统计学的方式,自动分析所读入的数据的字节流,从而得出最有可能的编码类型。chardet
本身支持多种编码,包括 Unicode(UTF-8, UTF-16 等)、ISO-8859 系列、Windows codepages 等。使用 chardet.detect()
函数,我们可以省去自己手动分析字节流的麻烦,快速准确地获得编码类型。
以下是 chardet.detect()
的基本介绍:
chardet.detect()
函数的唯一参数为 bytes 类型的数据,即二进制数据字节流。- 该函数的返回值是一个字典类型的对象,其中包含了编码类型和概率。返回值中包含了三个键值对:
encoding
:表示数据的编码类型。confidence
:是一个 0~1 之间的浮点数,表示对encoding
的判断可信度。language
:表示检测到的语言类型。
- 使用
chardet.detect()
函数时,需要注意以下几点:- 输入数据要求为二进制数据。如果读取的数据以字符串的形式存在,需要先进行
encode()
函数的操作,将字符串转化为二进制数据。 - 对于小数据量的编码检测结果不一定准确。通常情况下,
chardet
因为其统计学的方法,能够自动检测出数据的编码类型,但是对于数量较少的字节流,可能会检测出多个编码类型,准确度相对较低。相对来说,在对较大的数据进行编码检测时,准确度会更高。 - 不能保证返回结果是唯一的。由于不同编码之间存在一定的相似性,因此
chardet.detect()
函数不能保证返回结果是唯一的。例如,对于日语数据,有可能得到 Shift_JIS、EUC_JP、ISO-2022-JP 以及 UTF-8 等多种编码类型的结果。
- 输入数据要求为二进制数据。如果读取的数据以字符串的形式存在,需要先进行
其它使用
有了上述基础,做批量处理时就比较方便了,比如获取文件内容:
# function: 获取文件内容
# param: file_path
# return: contents
def read_file_contents(file_path):
encoding = detect_encoding(file_path) # 上述编写的函数
with open(file_path, "r", encoding=encoding) as f:
contents = f.read()
# ..... or do other thing
return contents
总结
使用 chardet.detect()
能解决大部分问题,但是其原理觉得不可能 100% 准确,所以使用需谨慎,另外,有性能要求的也需要做好取舍。