python字符编码

字符编码介绍

什么是字符编码

这里的字符指的是 人类能识别的字符,字符方便记忆。在计算机中,都是按照二进制存储,方便存储的是数字,因此,字符在计算机中的存储须要先转换为数字,而后再进行存储。
存储过程:字符 --> 数字,读取过程:数字 --> 字符 ~
以上两个转换过程当中,字符和数字之间存在一个一一对应的关系,一个字符对应一个特定的数字,这个一一对应的关系就是所谓的字符编码~python

字符编码问题

计算机出现以后,美国人搞出了一套ASCII,以下图。ASCII表中一个字符使用一个字节来表示,一个字节8位,最多只能表示256个字符(2**8 = 256)。表中的字符包括英文、字母、数字,还有一些特殊字符,这些字符和数字 之间存在一一对应关系,例如:97表示小写的a,65表示大写的A...
python字符编码windows

其实ASCII仅使用了一个字节中的7位来表示字符,一共127个字符(后128个称为扩展ASCII码)。ASCII是美国人发明的,因此除了英文,不能用于其余语言。因而中国人就指定了gb2312编码,其中包含了中文在内的字符 --> 数字的对应关系,日本人也制定了 Shift_JIS 编码,韩国人的 Euc-kr 编码等等,各国的人都有本身的一套标准。网络

这样在使用过程当中,例如,一篇文档中仅有一种语言,那么 就不存在问题;可是若是这篇文档中存在多种语言,那么不论是用哪一种编码标准,都会存在乱码问题,这时候 unicode 就应运而生,unicode 可以兼容万国字符,从而避免以上状况出现的乱码问题~ide

unicode介绍

unicode 经常使用2个字节(16位二进制)表明一个字符,生僻字须要用4个字节。unicode 兼容 ascii,例如:小写字母x,用 ascii 表示是 0111 1000(二进制),使用 unicode 表示 为 0000 0000 0111 1000(二进制),可见 二者的值一致,只是使用 unicode 表示使用了2个字节,而是用 ascii 表示仅使用了一个字节,存储空间多了一倍~编码

unicode 中存放了与其余编码的映射关系,因此 unicode 能够兼容 万国字符。"unicode 中存放了与其余编码的映射关系" 这句话是否是很差理解,简单的说就是,unicode 编码 能够转为 其余编码,例如gbk、Shift_JIS等,其余的编码也能够经过 unicode 中存在的映射关系 转为 unicode 编码,转换的规则以下图:
python字符编码code

经过以下示例来更进一步的解释,这张图表示 unicode 编码 和 gbk 等其余编码的映射关系(unicode映射表,截取而来),中文 '人' 字的 unicode 编码是 '4eba',对应的 gbk 编码是 '484b'
python字符编码orm

python3环境blog

>>> x = '\u4eba'                # unicode 码
>>> x
'人'
>>> x.encode('gbk')         # 转为 gbk 编码
b'\xc8\xcb'

>>> b'\xc8\xcb'.decode('gbk')    # gbk 编码转为 unicode 码
'人'

单引号或双引号中以 \u 开头的都是 unicode 码,unicode 码对每个字符用4位16进制数表示。具体规则是:将一个字符(char)的高8位与低8位分别取出,转化为16进制数, 若是转化的16进制数的长度不足2位,则在其后补0,而后将高、低8位转成的16进制字符串拼接起来并在前面补上 "\u" 。 ip

汉子 '中' 由 unicode 编码转为 gbk 编码后,显示的 gbk 编码为 'c8cb',和图中的 '484b' 便不符合,这是由于GBK 的编码为了兼容 ASCII,即若是是英文,就用一个字节表示,2个字节就是中文,若是1个字节的第一位(最左边一位)是0表示是 ASCII,若是连续的2个字节的第一位都是1,那么这2个字节表示为一个中文,因此这里的 'c8cb' 去掉首位的1后,就是 '484B' ~内存

unicode 和 UTF-8

ASCII 使用一个字节表示一个字符,而 unicode 须要2个字节,这样对于英文的文本而言,存储空间就多了一倍,因而就有了 UTF-8(可变长存储,Unicode Transformation Format),UTF-8 简称万国码,能够统一显示中文简体繁体及其它语言(如英文,日文,韩文)。UTF-8 编码中英文字符只使用1字节表示,中文字符用3字节,其余生僻字使用更多的字节存储~
 
在内存中的字符统一使用 unicode 编码,这样能够避免乱码问题,当数据须要存储到硬盘或者在网络之间进行传递时,再将 unicode 编码转为 其余编码标准(如今大多数状况都是UTF-8,也推荐使用UTF-8),由于这样更节省空间,也能够减少网络的传输压力。

当数据须要从新读入内存,就须要经过解码转为 unicode,以前使用何种方式编码存放到磁盘,就须要使用同一种编码标准进行解码。大体过程以下(UTF-8):

unicode(内存) -----> encode 编码 -------->utf-8(磁盘)
utf-8(磁盘) --------> decode 解码 ---------->unicode(内存)

 
这样也许有人会问,为何内存中不直接使用 utf-8 编码标准,utf-8 中囊括了全部语言,那是由于如今不少软件还在使用各国的编码标准(例如Shift_JIS,GBK,Euc-kr的等),utf-8 编码标准中不存在 和这些编码的映射关系(简而言之就是 Shift_JIS,GBK,Euc-kr等这些编码没法转换为 utf-8编码,utf-8编码也不能转换为这些编码),而 unicode 中存在,因此内存中一概使用 unicode 编码标准能够避免乱码问题。utf-8 的出现主要是为了减少存储的空间,若是哪一天全部的软件都是使用 utf-8 编码标准,那数据读取到内存中也不须要再转为 unicode。

常见的编码问题

常见的编码问题通常有2种:

--第一种状况
在数据存储时,编码错误。示例以下,文本中既有中文又有韩语,可是在存储时使用 Euc-kr 编码标准
python字符编码

保存后从新打开:
python字符编码

出现如上状况的问题在于,在使用Euc-kr 编码存储时就已经发生了错误,韩文使用 Euc-kr 编码(unicode --> Euc-kr)没有问题,可是中文这个过程没法完成,致使编码失败,数据没法恢复~

--第二种状况
数据正确编码后存储,在读取时使用了错误的编码
文本中只有韩文,且使用 Euc-kr 编码后保存
python字符编码

从新 使用其余编码标准 解码后打开
python字符编码

出现了乱码,文本编码后存储没有问题,可是在打开文件时使用了错误的解码方式。这里只要调整解码方式就能够,不会致使数据丢失!
python字符编码
从新设置成 Euc-kr 就能够

总结:
一、内存中字符的存储都是使用 unicode 编码,在写入到磁盘或者进行网络传输时才会将 unicode 编码转换成其余编码标准
二、在写入到磁盘上或者进行网络传输时,使用什么编码标准 进行编码,以后就须要使用一样的编码标准进行解码

三、推荐使用 utf-8 编码标准,多国的文字能够同时存在于一个文本中~
python字符编码

python中的编码

py文件的编码

执行python程序,首先会启动 python解释器,而后 python解释器会以 py文件 最前面2行指定的编码方式来将py文件的内容读入内存,定义编码经常使用的方式以下:

1)# coding=<encoding name>
2)# -*- coding: <encoding name> -*-

如上语句必须放在py文件的第一行或者第二行~

若py文件中不指定编码方式,则 python2 默认使用 ASCII,python3 默认使用 UTF-8。这个能够经过sys.getdefaultencoding() 查看
python2环境

luyideMacBook-Pro:~ baby$ python
Python 2.7.10 (default, Oct  6 2017, 22:29:07) ...
>>> import sys
>>> sys.getdefaultencoding()
'ascii'

python3环境

C:\Users\Baby>python
Python 3.6.4 (v3.6.4:d48eceb, Dec 19 2017, 06:54:40)...
>>> import sys
>>> sys.getdefaultencoding()
'utf-8'

python解释器加载代码到内存后,代码在内存中都是以 unicode 的格式存放的,可是当解释器执行到存放字符串的语句时,例如:my_str = 'hello kitty',python解释器会申请内存,而后将字符串编码成 py文件开头指定的编码格式进行编码,而后存放。python2中都是以上述过程存放字符串的;在python3中,字符串统一都是用 unicode 格式存放,python3中这样作 避免了不少没必要要的麻烦~~

python2中的str和unicode类型

--str类型
如上所说,python2中的字符串都是以 py文件开头指定的编码格式进行编码后存放
python2环境

# -*- coding: utf-8 -*-

my_str = '你好'
print type(my_str)
print (my_str,)

输出结果:
<type 'str'>
('\xe4\xbd\xa0\xe5\xa5\xbd',)

Tip:查看字符串在内存中存放的真实格式,能够经过print元组或列表查看,直接print 会自动转换编码~

--unicode类型
python2环境

# -*- coding: utf-8 -*-

my_str = u'你好'
print type(my_str)
print (my_str,)

输出结果:
<type 'unicode'>
(u'\u4f60\u597d',)

Tip:字符串前面加个u,即字符串保存为 unicode 格式~

unicode字符串 可经过编码,转换为其余编码格式保存

# -*- coding: utf-8 -*-

my_str = u'你好'
print (my_str.encode('utf-8'),)

输出结果:
('\xe4\xbd\xa0\xe5\xa5\xbd',)

python3中的str和bytes类型

在python3中,python解释器将字符串保存至新申请的内存上,默认使用的就是unicode。

x = '你好'                  # 默认就使用unicode保存到内存中,前面无需加 u
print(type(x))            # <class 'str'>

y = x.encode('utf-8')
print(y)                       # b'\xe4\xbd\xa0\xe5\xa5\xbd'
print(type(y))              # <class 'bytes'>

python3中申明 bytes 类型
x = bytes('abc'.encode('utf-8'))
y = b'abc'

print(type(x))        # <class 'bytes'>
print(type(y))        # <class 'bytes'>

Tip:
1)python3中的字符串默认就是以unicode形式保存,与python2中的 x = u'你好' 语句相似
2)python3中的字符串 x = '你好' 使用 utf-8 编码后输出的结果是 b'\xe4\xbd\xa0\xe5\xa5\xbd',这与python2中的 "my_str = '你好';print ((my_str,))" (# -- coding: utf-8 --)输出结果一致。.....python2中的 str 类型就是 python3 中的 bytes 类型~

查看python2中的 bytes 源代码:
python字符编码

python2中的bytes是为了兼容python3的写法,python2 中 bytes 类型直接使用了str类型,因此:
python2中的字符串有3种类型:unicode、str、bytes,其中bytes和str为同一个类型~
python3中的字符串有2种类型:str 和 bytes,str就是python2中的unicode,bytes就是python2中的str~

sys模块中的getdefaultencoding和setdefaultencoding

使用sys模块中的getdefaultencoding可获取python的默认编码方式:

# python2
import sys
print sys.getdefaultencoding()
输出结果:
ascii

# python3
import sys
print(sys.getdefaultencoding())

输出结果:
utf-8

能够看到python2中的默认编码是ascii,python3中的是utf-8。字符串在encode和decode时(转换为unicode或从unicode转为其余编码)默认使用getdefaultencoding输出的编码格式,这个在python2中应用较多,python3中因为字符串一概使用unicode存放,因此应用较少~

python3中,当str类型(unicode)和bytes类型合并时,会直接报错

x = '你好,'                               # str类型
y = '贝贝'.encode('utf-8')        # bytes类型
print(x + y)

报错信息:
TypeError: must be str, not bytes

可是在python2中,这个过程能够进行,Python解释器会自动把 str 转换成 unicode 再进行运算,运算结果也都是 unicode类型,在Python解释器自动将 str 转成 unicode时,因为没有具体指定使用哪一种编码进行转码,因此python解释器就会默认使用 getdefaultencoding中的编码,python2中默认编码是ascii,因而就出现以下错误:

# -*- coding: utf-8 -*-

x = u'你好,'
y = '贝贝'
print x + y

错误信息:
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe8 in position 0: ordinal not in range(128)

调整一下默认编码,就能够正常输出:

# -*- coding: utf-8 -*-

import sys
reload(sys)
sys.setdefaultencoding('utf-8')
x = u'你好,'
y = '贝贝'
print x + y

输出结果:
你好,贝贝

字符串打印到终端

python2中字符串直接输出到终端 和 字符串的编码标准(以什么标准编码存放在内存上)即 终端编码有关(例如windows终端编码为gbk,pycharm终端编码为utf-8),二者一致,才能避免乱码

python3中有所区别,字符串默认使用unicode格式保存在内存中,这样不管输出到哪一个终端都不会有乱码问题;若将字符串转为其余编码格式,则终端不会将其转为字符格式,而是原样输出

x = '你好'
y = x.encode('utf-8')
print(type(x))
print(x)

print(type(y))
print(y)

pycharm 输出结果:
<class 'str'>
你好
<class 'bytes'>
b'\xe4\xbd\xa0\xe5\xa5\xbd'

python字符编码

二者输出结果一致~.................^_^

相关文章
相关标签/搜索