默认讨论的都是Python3.6。html
计算机的存储与计算都是以二进制的形式进行的;所以对于逻辑符号Char(数字,字母,中文,数学字符,其余字符如制表符)须要有对应的二进制码表示,这就是编码的做用。java
编码有两个方面,一个是字符集,一个是字符集对应的编码规则/算法。通常来讲,人们认为Unicode编码是一种字符集,utf-8与utf-16是具体的字符编码规则/算法。python
可是若是要把unicode看作编码规则也是能够的,有n个字符就用十进制n的二进制形式来表示这个字符集便可,最先的ascii码就是这样作的。可是这样很难实现unicode做为万国码须要知足的一些特性:1.向下兼容,2.易于拓展,3.兼顾存储与传输性能。linux
ASCII(American Standard Code for Information Interchange,美国标准信息交换代码)是基于拉丁字母的一套电脑编码系统,主要用于显示现代英语和其余西欧语言。它是现今最通用的单字节编码系统,并等同于国际标准ISO/IEC 646。web
标准 ASCII 码使用 7 个二进位对字符进行编码。基本的 ASCII 字符集共有 128 个字符,其中有 96 个可打印字符,包括经常使用的字母、数字、标点符号等,另外还有 32 个控制字符。0~31表示控制字符如回车、退格、删除等;32~126表示打印字符便可以经过键盘输入而且能显示出来的字符。!
在ASCII中,字符集(charset)编码与编码encoding方案等价。而UNICODE中字符集(charset)编码与编码encoding方案不等价。算法
ASCII只能表示128个字符,显示是不能彻底表示完的,因此ISO-8859-1(latin-1)扩展了ASCII编码,在ASCII编码之上又增长了西欧语言、希腊语、泰语、阿拉伯语、希伯来语对应的文字符号,它是向下兼容ASCII编码的。sql
ASCII是由美国国家标准学会(American National Standard Institute , ANSI )制定的,是一种标准的单字节字符编码方案,用于基于文本的数据;ascii是ansi标准,包含128个字符(7 bits)。数据库
可是,咱们常说的ANSI编码,一般特指windows平台的一种基于ANSI标准的ASCII扩展码,他将ASCII码扩展到8bits,增长了0x80-0xff共128个字符。ANSI码仅在前126个与ASCII码相同。vim
GBK,全称为Chinese Internal Code Specification,即汉字内码扩展规范,于1995年制定[gb2312为1980年]。它主要是扩展了GB2312,在它的基础上又加了更多的汉字,它一共收录了21003个汉字。GBK是向下兼容GB2312编码的,也就是说GB2312编码的汉字能够用GBK正常解码不会出现乱码,但用GBK编码的汉字用GB2312解码就不必定了。windows
GB18030全称汉字内码扩展规范,是如今最新的内码字集于2000年发布,并于2001年强制执行,包含了中国大部分少数民族的语言字符,收录汉字数超过70000余个。
它主要采用单字节、双字节、四字节对字符编码,它是向下兼容GB2312和GBK的,虽然是我国的强制使用标准,但在实际生产中不多用到,用得最多的反而是GBK和GB2312。
为了本身的语言能在计算机中正常显示,每一个国家和地区都有各自的编码,因此编码多了谁也不认识对方的编码,这时候ISO组织就提出了一种新的编码叫UNICODE编码让全球的文化、字符、符号都能支持。UNICODE在制定时计算机容量已不是问题,因此设计成了固定两个字节,全部的字符都用16位表示,包括以前只占8位的英文字符等,因此会形成空间的浪费,UNICODE在很长的一段时间内都没有获得推广应用。
UNICODE能够理解为一种字符集映射方案;基于该方案也能够直接进行二进制编码(例如utf-16实现),可是效率会比较低,所以又产生了utf-8实现。
UTF-16是UNICODE的具体实现,16即16位,UTF-16便是这个来由,定义了UNICODE字符在计算机中的存储方式,UTF-16一样使用了两个字节来表示任何字符,这样使得操做字符串很是高效,这也是java把UTF-16做为字符在内存中存储的格式的重要缘由。
虽然UTF-16很高效,但也是UNICODE最大的坏处,使得全部单字节字符必定要占两个字节,存储空间放大了一倍,这明显消耗了资源,不符合如今互联网高速发展的现状。因此有了UTF-8,它是UNICODE的一种可变长度字符编码的实现。
Python3严格区分了 str 和 bytes 两种类型。Python3不会以任意隐式的方式混用 str 和 bytes。所以使用者不能拼接字符串和字节包,也没法在字节包里搜索字符串(反之亦然),也不能将字符串传入参数为字节包的函数(反之亦然)。
>>> client.send("test str") Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: a bytes-like object is required, not 'str' >>> client.send(b"test str") #将参数转换成 bytes 类型 8 #返回发送的数据长度
以文本为例,Python在工做中会将文本数据读取到内存decode为unicode编码,前面说了unicode编码的UTF-16实现因为操做字符串很是高效,所以很适合在内存中使用。在用户的角度,这些decode为unicode编码的字符就是Python中的str。
在内存中完成运算以后,将文本数据写回到磁盘中,须要将数据再encode为utf-8(通常状况下使用utf-8,其余的也是能够的)。在用户的角度,这些encode为utf-8的字符就是Python中的bytes。
>>> b = bytes('中文', 'utf-8') >>> b b'\\xe4\\xb8\\xad\\xe6\\x96\\x87' >>> b.decode('Windows 1252') 'ä¸\\xadæ–‡' >>> b.decode('ISO8859-7') 'δΈ\\xadζ\\x96\\x87' >>> string = b.decode('utf-8') >>> string '中文' >>> b = string.encode('utf-8') >>> b b'\\xe4\\xb8\\xad\\xe6\\x96\\x87'
咱们能够将Python工做区看做一个水池,一个入口负责从硬盘读取内容转为unicode到内存进行运算与处理,一个出口负责将内存中的数据转为utf-8或者其余编码形式保存到硬盘中。
通常出如今数据读取中。缘由为系统默认编码类型与文件保存时的编码类型不一致。
sys.getdefaultencoding() 'utf-8'
vim 打开文件,切换到底线命令模式,在最底一行输入以下命令:
:set fileencoding fileencoding=utf-16le
除此以外,还有基于file指定,enca指定的方式。
哪一个高效用哪一个便可。
通常出如今数据输出中,例如print过程当中可能出现的:UnicodeEncodeError: 'ascii' codec can't encode character '\\U0001f621' in posit。
标准输出即Python中的print(); print方法调用以后会根据默认的编码方式将要print的str从unicode转化为对应的编码并交接给操做系统,最后在显示屏上输出。
如下指令能够查询默认的标准输出编码方法:
>>> import sys >>> sys.stdout.encoding 'ANSI\_X3.4-1968'
'ANSI_X3.4-1968' 只能支持标准的ascii码字符输出,那么怎样可以修改默认的标准输出编码标准从而支持更多的输出字符呢?
1. 修改环境变量
export PYTHONIOENCODING=utf-8
2. 每次运行脚本时带上
有的时候可能并不想改动环境变量,那么就直接在脚本前指定。
PYTHONIOENCODING=utf-8 python code.py
3. 代码中修改
import codecs sys.stdout = codecs.getwriter("utf-8")(sys.stdout.detach()) sys.stdout.write("Your content....")
4. 操做系统设定
更改系统默认的语言编码设定,从而默认标注输出为utf-8。最简单的一种处理方式以下,该方式不必定能支持中文,可是范围确定大于ASCII码。
LC_ALL=C.UTF-8
有时候往文本文件或者数据库写入也会遇到编码报错(例如用默认的ASCII码去编码中文字符),解决办法通常为指定写入的编码方式。
# 指定将str编码为bytes的标准为utf-8(也是默认的) with open('test.txt', 'w', encoding='utf8') as f: f.write('something') # 'wb'模式只能直接写入bytes类型 with open('test.txt', 'wb') as f: f.write('something'.encode('utf-8'))
在实际的开发过程当中,只理解Python的编解码模型是不够的,还须要有一个更加宏观的认识,例如Python与操做系统的编解码关系,Python与其余软件组件的编解码关系。
数据库通常都有客户端和服务端。例如在A机器上进行项目开发,在B机器上部署数据库,那么A机器上的sqlclient就是客户端,B机器上的sqlserver就是服务端;A机器须要经过网络远程与B机器的数据库进行交互完成数据的读写。
在A机器上,从B机器的sqlserver读写文件都统一用utf-8则不会有什么问题;可是在B机器上若是要本地读取数据则可能须要特别设置读取的编码类型为utf-8,否则可能会出现读出来乱码的问题。
程序运行使用一套语言须要有字符集(数据)和字体(显示),Locale是根据计算机用户所使用的语言,所在国家或者地区,以及当地的文化传统所定义的一个软件运行时的语言环境。
在locale环境中,有一组变量,表明国际化环境中的不一样设置;其中有一个叫作LC_CTYPE ,用于字符分类和字符串处理,控制全部字符的处理方式,包括字符编码,字符是单字节仍是多字节,如何打印等。是最重要的一个环境变量。若是在开发过程当中遇到了编码问题,操做系统自己的语言环境也是须要去斟酌考虑的。
更多细节参考
https://www.cnblogs.com/rusking/p/3695993.html
为了确保后台流程编解码的顺畅进行,最好将系统环境编码,文本编辑器,文件编码和数据库编码设置为同样的。
在Python2中,py文件的默认编码是ASCII,在源代码文件中,若是用到非ASCII字符,须要在文件头部进行编码声明;Python3默认源文件编码为utf-8。
1. 架构师必须掌握的各类编码
http://www.javashuo.com/article/p-mcymxpng-pb.html
2. PYTHON编码和解码
https://blog.csdn.net/can0227/article/details/83240705
3. linux查看文件编码格式