Python编码避坑指南-编码转换实战

  在之前的知识分享中(Python编码避坑指南——编码基础知识),我们为大家介绍了ASCII、Unicode、UTF-8等编码的相关概念。大家理解了这些编码概念之后,我们今天就来具体说说不同编码之间该如何转换;当我们处理的文本文件中包含中文的时候,我们如何才能正确读取文本文件中的内容。

1. 中文常见编码:GB2312、GBK

  计算机最早是由美国发明的,他们制定了ASCII 码(前面文章有提到过,详情查看:Python编码避坑指南——编码基础知识)。后来计算机发展越来越广泛,世界各国为了可以在计算机保存他们的文字,用127号之后的空位来各种字符,从128到255这一页的字符集被称”扩展字符集”。但是原有的编号方法,已经再也放不下更多的编码。

  • GB2312
    等中国人们得到计算机时,已经没有可以利用的字节状态来表示汉字,况且有6000多个常用汉字需要保存呢。于是国人就自主研发,把那些127号之后的奇异符号们直接取消掉。规定:一个小于127的字符的意义与原来相同,但两个大于127的字符连在一起时,就表示一个汉字,前面的一个字节(他称之为高字节)从0xA1用到 0xF7,后面一个字节(低字节)从0xA10xFE,这样我们就可以组合出大约7000多个简体汉字了。在这些编码里,我们还把数学符号、罗马希腊的字母、日文的假名们都编进去了,连在 ASCII 里本来就有的数字、标点、字母都统统重新编了两个字节长的编码,这就是常说的”全角”字符,而原来在127号以下的那些就叫”半角”字符了。中国人民看到这样很不错,于是就把这种汉字方案叫做 “GB2312″。GB2312 是对 ASCII 的中文扩展。

  • GBK
    但是中国的汉字太多了,后来还是不够用,于是干脆不再要求低字节一定是127号之后的内码,只要第一个字节是大于127就固定表示这是一个汉字的开始,不管后面跟的是不是 扩展字符集里的内容。结果扩展之后的编码方案被称为 GBK 标准,GBK 包括了 GB2312 的所有内容,同时又增加了近20000个新的汉字(包括繁体字)和符号。后来少数民族也要用电脑了,于是我们再扩展,又加了几千个新的少数民族的字,GBK 扩成了 GB18030。从此之后,中华民族的文化就可以在计算机时代中传承了。

2. 通过Unicode编码进行不同编码之间的互相转化

  不同的编码之间不能互相识别,不能相互转化,会报错或出现乱码。Python3默认的编码是Unicode,如果我们希望实现不同编码之间的互相转换, 都要先decode解码为unicode编码, 然后通过unicode再encode编码为想要的编码。

  • Unicode 转换为 GB2312
    a = 'Python与临床科研' #由于Python3 的字符串类型默认为Unicode,所以不需要decode()
    unicode_gb2312 = a.encode('gb2312')
    print(a, '[gb2312]', unicode_gb2312)
    
    输出结果:
    Python与临床科研 [gb2312] b'Python\xd3\xeb\xc1\xd9\xb4\xb2\xbf\xc6\xd1\xd0'
    
  • GB2312 转换为 Unicode
    gb2312_unicode = unicode_gb2312.decode('gb2312')
    
  • GB2312 转换为 UTF-8
    转换步骤:GB2312 -> Unicode -> UTF-8
    gb2312_utf8=unicode_gb2312.decode('gb2312').encode('utf-8')
    print(a,'[utf-8]',gb2312_utf8)
    
    输出结果:
    Python与临床科研 [utf-8] b'Python\xe4\xb8\x8e\xe4\xb8\xb4\xe5\xba\x8a\xe7\xa7\x91\xe7\xa0\x94'
    
  • UTF-8 转换为 GB2312
    转换步骤:UTF-8 -> Unicode -> GB2312
    utf8_gb2312 = gb2312_utf8.decode('utf-8').encode('gb2312')
    
  • UTF-8 转换为 GBK
    utf8_gbk=gb2312_utf8.decode('utf-8').encode('gbk')
    
  • GBK 转换为 UTF-8
    gbk_utf8 = utf8_gbk.decode('gbk').encode('utf-8')
    
    总结:如果是unicode与其他编码之间的转换,直接采用decode('编码类型')将其他编码转换为unicode,采用encode('编码类型')将unicode的编码转换为其他编码类型。其他编码之间转换都要先decode解码为unicode编码, 然后通过unicode再encode编码为想要的编码。

3. 简单解决Python文件中文编码问题

  • 已知文件编码类型
    添加encode参数,使为对应的文件编码类型。

    import pandas as pd
    pd.read_csv("example.csv",encoding='gb2312')
    
  • 文件编码类型未知 / 批量处理时多个文件编码类型不同
    对于未知编码的文本文件,要把它转换成字符串,需要先“猜测”编码。猜测的方式是先收集各种编码的特征字符,根据特征字符判断,就能有很大概率“猜对”。当然,我们肯定不能从头自己写这个检测编码的功能,这样做费时费力。chardet这个第三方库正好就派上了用场。用它来检测编码,简单易用。

    安装chardet
    如果安装了Anaconda,chardet就已经可用了。否则,需要在命令行下通过pip安装:

    conda install -c anaconda chardet
    

    使用chardet

    import chardet
    import pandas as pd
    
    # 获取文件编码类型
    def get_encoding(file):
        # 二进制方式读取,获取字节数据,检测类型
        with open(file, 'rb') as f:
            return chardet.detect(f.read())['encoding']
    
    filename = "example.csv"
    # 根据文件编码读取文件内容
    pd.read_csv(filename, encoding=get_encoding(filename))
    

4.【更新】批量转换文件编码

看到有朋友在评论区提问批量转换文件编码,特更新以下代码,利用chardet和循环遍历目录,实现批量编码转换。
代码参考自博主「罗小通」

# -*- coding: utf-8 -*-
import os, chardet, codecs, re
#文件类型扩展名  文件列表
FileType, FileList = [], []

def get_file_list(Dir):
# 获取指定目录下所有指定类型文件

    if len(Dir.strip(' ')) == 0:
        return 
    dirList = [os.path.join(Dir, f) for f in os.listdir(Dir)]
    fileList = [f for f in dirList if os.path.isfile(f) and os.path.splitext(f)[1] in FileType]
    folderList = [f for f in dirList if os.path.isdir(f)]
    FileList.extend(fileList)
    # 递归字文件夹
    for subfolder in folderList:
        get_file_list(subfolder)
    

def convert_2_target_coding(coding='utf-8'):
# 转换成目标编码格式

    for filepath in FileList:
        with open(filepath, 'rb') as f:
            data = f.read()
            codeType = chardet.detect(data)['encoding']

        if codeType not in (coding, 'ascii'):
            with codecs.open(filepath, 'r', codeType) as f:
                content = f.read()
            with codecs.open(filepath, 'w', coding) as f:
                f.write(content)
            print(filepath + '\n')

            
if __name__ == '__main__':
    # 获取目录
    WorkDir = str(input('input target folder\n\t:'))
    # 目标编码格式
    TargetCoding = str(input('target coding(default to utf-8)\n\t:')).lower()
    # 文件类型扩展名
    FileType = re.split(r'\s+', str(input('file type(filename extension, such as .c .h)\n\t:')))
    os.chdir(WorkDir)
    get_file_list(WorkDir)
    convert_2_target_coding(TargetCoding)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,905评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,140评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,791评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,483评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,476评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,516评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,905评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,560评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,778评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,557评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,635评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,338评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,925评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,898评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,142评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,818评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,347评论 2 342