python在升级到Python3之后,因为Utf-8作为没有歧义的统一标准编码,相信很少人再会碰到编码格式的问题,但现实总会不停地打脸理想,告诉我们Too Young Too Simple。先不扯闲篇,直入主题,介绍一下这篇博文主要的知识,后面再结合具体的软件工作情境来详细说明为什么会碰到此类问题。

  1. Python2中纠结的编码格式。
  2. Python3中的大一统。
  3. 实战分析
  4. 小结

Python2中的编码格式

首先我们需要理解,在计算机中,所有的内容,归根结底就是一个个的字节甚至是0与1,没有中文日文也没有abcd。但为了在磁盘中存储这些文字,我们发明了编码。比如一个字符'a'被编码成了十进制的97,这是ASCII编码,但是中文表达不了啊,于是又有了一种编码格式GBK,但是日文表达不了啊,算了,大一统吧,于是就有了Utf-8,可变字节,可以表示基本当前所有的字符了。而解码呢,就是将编码的二进制再还原为抽象的字符'a',或者一个文字'中',这个抽象的字符,就可以理解为Unicode字符。

有了上面的基础,我们就来看看有哪些地方需要用到编码吧。

#!/usr/bin/env python2
# -*- coding:GB2312 def main():
a = '中文'
with open('E:/a.txt', 'w') as f:
f.write(a) if __name__ == '__main__':
main()

此处的声明有两个用处,一是解释器将以怎样的编码格式来读取源码文件,二是出现在内存中的字符变量是被怎样编码的。基于前者,我们应该保证我们的源码文件在保存时,也应该选择GB2312的格式来保存,基于后者,我们可以预期,输出的a.txt文件的格式也将是GB2312。

那不好意思,我想输出文件的格式为utf-8,这可咋整?先把这个变量解码为Unicode,然后再重新编码成utf-8的字符输出就行了。

#!/usr/bin/env python2
# -*- coding:gb2312 -*-
def main():
a = '中文'
b = a.decode('gb2312') # Unicode类型,也就是b = u'中文'
c = b.encode('utf-8')
with open('E:/c.txt', 'w') as f:
f.write(c) if __name__ == '__main__':
main()

所以,对于'中文'这两个字符来说,在上面的程序中,就有了3个变量,a和c都是str,而b是Unicode。而Unicode因为是个抽象出来的东西,所以无论是print还是想f.write都是不收的,因为输出都需要确切的编码成二进制的数据,就向水通过不同的管道流向不同的容器。这里也可以顺便解释一下为什么有的时候,print在IDE里面执行得好好的,到了命令行控制台就成了乱码呢?因为不同的控制吧,其默认的解码方式不一样,你像中文的Windows操作系统,就是GB2312的,而Linux或者IDE中的输出控制台则默认为Utf-8的。

想到上面程序中的abc,会不会脑壳疼? 那接下来看python3怎样破而后立。

Python3中的大一统

从使用者的角度来看,Python3最大的升级就是将Python2中混乱的编码格式进行了统一。既然上面程序中的a和c,编码格式看起来是让人混乱的,那我们索性就统统不要,将其统一到Unicode上来。所以,在Python3中, 基本的字符表示使用类型str,可以将其理解为Unicode,而我要编编码后的对象怎么表示呢,来来来,bytes类型也已经给你准备好了。就这样?对,就这样。

实战分析

注意:以下的场景,除非特别说明,都以Python3作为编码语言。

  • 写文件

在python3中,因为str类型即为Unicode,不与具体编码挂钩,所以,在输出时只需要使用file对象的write方法的encoding参数来指定编码格式即可,默认为utf-8。

  • 读文件

写文件,我们可以指定编码格式,那么读文件我们应该使用什么编码格式来读取文件呢?因为历史原因,有些文件格式很古老,在创建之初,并没有想到后面还会有这么多的编码格式,这么多的程序需要来对其进行解析,所以这个坑就挖下了。理想情况,大家都用utf-8,次之,大家在文件开始都声明一下自己的编码格式,但很遗憾,这两点都因为历史已经形成而无法做到,那么剩下的其实就是。你没有看错,其实就是。从使用最广泛的编码开始试,如果通过了,就表示Ok,如果有错,就换个再试试。那如果一个文件很变态,前面一种编码,后面一种编码呢?或者前面用ascii编码解析的都OK,后面多了中文又解析不了呢,而操蛋的是这个中文在1GB之后的位置出现了!惊喜不惊喜?讲这么多是想告诉大家,这个问题没有最优解。就是拿出文件中的一段来进行解析尝试。

import chardet

def get_file_encoding(file_path):
"""
获取文件的编码格式
:param file_path:
:return:
"""
with open(file_path, "rb") as f:
data = f.read(1024*1024)
encoding = chardet.detect(data).get('encoding')
if encoding.lower() == 'gb2312':
encoding = 'gb18030'
if encoding.startswith('ISO-8859-'):
encoding = 'gbk'
# 用来解决出现一些奇奇怪怪地编码
if encoding.lower() not in ('gbk', 'gb18030', 'utf-8', 'utf-16', 'ascii', 'utf-8-sig'):
encoding = 'gb18030'
return encoding

为什么会有这么奇怪的方法?chardet搞不定么?真搞不定。如果代码可以优化,请大家务必告诉我。

小结

绝大多数的程序,都是接受一段输入,经过运算后,进行一段输出。我们无法控制这种输出的来源,可能是控制台输入,可能是网络端口,可能是Unix中的一段通信管道,或者是各种文件。那为了我们处理中的一致性,我觉得我们应该在python3中统一使用str,而在python2中unicode。而在输出时,统一为utf-8的编码,不要再为后来者挖坑。在此,请允许我摘录自《编写高质量Python代码的59个有效方法》中的一段辅助函数,做为结尾。

# python3
def to_str(bytes_or_str):
if isinstance(bytes_or_str, bytes):
value = bytes_or_str.decode('utf-8')
else:
value = bytes_or_str
return value # python2
def to_unicode(unicode_or_str):
if isinstance(unicode_or_str, unicode):
value = unicode_or_str.decode('utf-8')
else:
value = unicode_or_str
return value

也谈Python编码格式的更多相关文章

  1. 【Python五篇慢慢弹(4)】模块异常谈python

    模块异常谈python 作者:白宁超 2016年10月10日12:08:31 摘要:继<快速上手学python>一文之后,笔者又将python官方文档认真学习下.官方给出的pythondo ...

  2. 解决python编码格式错误问题

    一:前言 遇到问题:print输入汉字时提示错误信息 UnicodeDecodeError: 'ascii' codec can't decode byte 0x?? in position 1: o ...

  3. 浅谈Python时间模块

    浅谈Python时间模块 今天简单总结了一下Python处理时间和日期方面的模块,主要就是datetime.time.calendar三个模块的使用.希望这篇文章对于学习Python的朋友们有所帮助 ...

  4. 浅谈Python在信息学竞赛中的运用及Python的基本用法

    浅谈Python在信息学竞赛中的运用及Python的基本用法 前言 众所周知,Python是一种非常实用的语言.但是由于其运算时的低效和解释型编译,在信息学竞赛中并不用于完成算法程序.但正如LRJ在& ...

  5. Python编码格式导致的csv读取错误

    Python编码格式导致的csv读取错误(pandas.read_csv) 本文记录python小白我今天遇到的这两个问题(csv.reader和pandas.csv_read): pandas模块“ ...

  6. 浅谈python字符串存储形式

    http://blog.csdn.net/zhonghuan1992 钟桓 2014年8月31日 浅谈python字符串存储形式 记录一下自己今的天发现疑问而且给出自己现有知识有的回答. 长话短说,用 ...

  7. 开发技术--浅谈Python函数

    开发|浅谈Python函数 函数在实际使用中有很多不一样的小九九,我将从最基础的函数内容,延伸出函数的高级用法.此文非科普片~~ 前言 目前所有的文章思想格式都是:知识+情感. 知识:对于所有的知识点 ...

  8. 开发技术--浅谈python数据类型

    开发|浅谈python数据类型 在回顾Python基础的时候,遇到最大的问题就是内容很多,而我的目的是回顾自己之前学习的内容,进行相应的总结,所以我就不玩基础了,很多在我实际生活中使用的东西,我会在文 ...

  9. 开发技术--浅谈python基础知识

    开发|浅谈python基础知识 最近复习一些基础内容,故将Python的基础进行了总结.注意:这篇文章只列出来我觉得重点,并且需要记忆的知识. 前言 目前所有的文章思想格式都是:知识+情感. 知识:对 ...

  10. 1-浅谈 python变量

    浅谈 python变量 python变量概念 程序执行的过程中,很多数据都在变化的过程,我们需要一种机制把这种变化体现出来,变量是我们记录这种变化的方式. python以及其它各种语言的变量 ,其作用 ...

随机推荐

  1. wpf CommunityToolkit.Mvvm8.1 MVVM工具包安装引用指南

    CommunityToolkit.Mvvm包(又名MVVM 工具包,以前名为 Microsoft.Toolkit.Mvvm)是一个现代.快速且模块化的 MVVM 库.它支持:.NET Standard ...

  2. 开源项目audioFlux: 针对音频领域的深度学习工具库

    目录 时频变换 频谱重排 倒谱系数 解卷积 谱特征 音乐信息检索 audioFlux是一个Python和C实现的库,提供音频领域系统.全面.多维度的特征提取与组合,结合各种深度学习网络模型,进行音频领 ...

  3. 部署:keepalived-1.3.5+MHA部署mysql集群

    MHA: MHA工作原理总结为以下几条: 从宕机崩溃的master保存二进制日志事件(binlog events): 识别含有最新更新的slave: 应用差异的中继日志(relay log)到其他sl ...

  4. layUI之DataTable组件V1.0(父子表管理传值/数据表格与select&laydate结合等)

    layUI之DataTable数据表格组件V1.0 目录 layUI之DataTable数据表格组件V1.0 概述 一.下载与引用 二.组件功能介绍 三.父表格渲染 1. HTML中声明空table一 ...

  5. 容器云平台监控告警体系(五)—— Prometheus发送告警机制

    1.概述 在Prometheus的架构中告警被划分为两个部分,在Prometheus Server中定义告警规则以及产生告警,Alertmanager组件则用于处理这些由Prometheus产生的告警 ...

  6. JUC中常见的集合

    Map: HashMap ===> ConcurrentHashMap List: ArrayList ===> CopyOnWriteArrayList Set: HashSet === ...

  7. 业务系统对接CAS

    启动类加@EnableCasClient <!--cas客户端--> <dependency> <groupId>net.unicon.cas</groupI ...

  8. Mac M系列芯片 vue前端node-sass兼容问题解决

    0.由于M系列芯片是arm架构,在使用brew安装node时都是arm的node,但是node-sass@4.14.1版本中不支持arm架构的出现如下报错: Error: Node Sass does ...

  9. 2021-10-07:将有序数组转换为二叉搜索树。给你一个整数数组 nums ,其中元素已经按 升序 排列,请你将其转换为一棵 高度平衡 二叉搜索树。高度平衡 二叉树是一棵满足「每个节点的左右两个子树

    2021-10-07:将有序数组转换为二叉搜索树.给你一个整数数组 nums ,其中元素已经按 升序 排列,请你将其转换为一棵 高度平衡 二叉搜索树.高度平衡 二叉树是一棵满足「每个节点的左右两个子树 ...

  10. OData WebAPI实践-兼容OData集合响应

    本文属于 OData 系列文章 引言 OData 是一个开放标准,已经在 oasis 组织标准化,因此我们可以在标准的官网查询到 OData 的标准请求与返回形式:OData JSON Format ...