python3.x 中批量处理不同编码的混合中英文字符文件

前言:这是之前处理一批老旧文件遇见的坑,在这批文件里面,有个记录更新历史的text文件,需要在场景文件做更新的同时记录下更新的内容,一顿操作之后发现在其中某些txt文件中新录入的中文是乱码,一番查证之下发现,这批文件里的编码并不相同,有些是默认的gbk,有些的utf-8…还有一些是全英文的ASCII…在python里面要处理字符串编码确实挺让人头疼的,以下细细说道。
ps:适用python3.x

一般读取文件方式

在python中对txt文件操作,需要先打开文件,再进行读写,这里使用使用Python内置的open()函数(具体该函数的使用在此不表,可参考官方文档):

with open('/Users/admin/test.txt', 'a') as f:
    f.write(u'你好!')

字符编码

由于系统默认创建的txt文件编码为“gbk”,而要读取非UTF-8编码的文本文件,需要给open()函数传入encoding参数)(ps:python2.x中没有此参数,可以不写):

with open('/Users/admin/test.txt', 'a', encoding='gbk') as f:
    f.write(u'你好!')

以上,是对已知编码的文件进行编辑的方式。

检测编码

那要对一批未知编码方式的文件进行操作,就需要先查询该文件的编码,python就有这么一个第三方库chardet,用它来检测编码(python默认没有这个库,需要自行安装),至此,这段代码有了第三个方案:

import chardet

def get_encoding(file):
    with open(file,'rb') as f:
        return chardet.detect(f.readline())['encoding']
        #{'encoding': 'utf-8', 'confidence': 0.99, 'language': ''}

txt_code = get_encoding('/Users/admin/test.txt')
with open('/Users/admin/test.txt', 'a', encoding=txt_code) as f:
    f.write(u'你好!')

在上面这段代码中,open(file,‘rb’)中的‘rb’是只用二进制模式去读取文件,这样不会造成因为对文件编码错误造成读取错误的,f.readline()仅去读取文件中第一行内容,便于节约资源

混合中英文字符

当txt文件中仅有英文字符时,使用上面那种方案,会因为chardet检测到的编码格式为ASCII而报以下错误:

UnicodeEncodeError: 'ascii' codec can't encode character '\xf1' in position 11: ordinal not in range(128)

再仔细排查,发现,无论是以“gbk”还是“urf-8”编码的纯英文文件,检测编码都是‘ascii’:

# gbk编码:英文是ascii,中文是GB2312(GBK的上一版中文字符集),language字段指出的语言是'Chinese'
print("str1", check_char("hello world".encode("gbk")))  # str1 {'encoding': 'ascii', 'confidence': 1.0, 'language': ''}
print("str2", check_char("你好".encode("gbk")))  # str2 {'encoding': 'GB2312', 'confidence': 0.99, 'language': 'Chinese'}


# utf-8编码: 英文还是ascii,中文是utf-8了,但是language没有指出,是因为utf-8适用的太多了
print("str3", check_char("hello world".encode("utf-8")))  # str3 {'encoding': 'ascii', 'confidence': 1.0, 'language': ''}
print("str4", check_char("你好".encode("utf-8")))  # str4 {'encoding': 'utf-8', 'confidence': 0.9690625, 'language': ''}

这就很头疼了,那要在纯英文字符后面添加中文字符究竟要使用哪一种编码呢???答案是,随便哪一种都可。。。。。于是,代码再次修改:

import chardet

def get_encoding(file):
    with open(file,'rb') as f:
        txt_code = chardet.detect(f.read())['encoding']
        #{'encoding': 'utf-8', 'confidence': 0.99, 'language': ''}
        if txt_code == 'ascii':
            return 'utf-8'
        return txt_code

txt_code = get_encoding('/Users/admin/test.txt')
with open('/Users/admin/test.txt', 'a', encoding=txt_code) as f:
    f.write(u'你好!')

在这段代码里,把f.readline()又改回了f.read(),因为很有可能在文件的第一行就遇见全英文,而中文字符躲在后面,指定的utf-8编码很可能不适合该文件而导致解码出错。

好,至此,纠结了好几个月的问题,终于解决了。。。撒花~~~

发布了7 篇原创文章 · 获赞 2 · 访问量 1496

猜你喜欢

转载自blog.csdn.net/u013148608/article/details/104494367