python3中字符串编码常见种类_Python基础篇—标准数据类型—String字符串编码问题...

我要开始写String编码问题了。。。脑壳疼。。

在String字符串的第一篇末尾有留一个坑,就是关于中文字符串编码。整个编码的故事说起来都是很费劲的,我也只能把我所知道的梳理整理一下,在日常敲码过程中碰到了问题还是需要额外参考度娘。

字符编码

最开始要从字符编码说起,在计算机的世界里只有0/1,也就是说计算机只能处理数字,那么需要处理文本时,就得同样将文本转为数字才能处理。最早计算机在设计时,为了运算方便,都是8个比特(bit)组成一个字节(Byte),所以一个字节可以表示的最大整数就是255(二进制 11111111 = 十进制 255 (2^8 - 1))。这个时候当你需要表示更大的整数怎么办?加字节,比如两个字节可以表示的最大整数是65525(2^16 - 1)。

由于计算机发源于美国,而英文世界里只有数字(0-9)+26个字母*2(大小写)+若干标点符号以及控制符,总数不多,用一个字节(8个bit)就可以表示所有的字符,最早只有127个字符被编码到计算机里,也就是大小写英文字母、数字和一些符号,这个编码表被称为ASCII编码( American Standard Code for Information Interchange,美国信息互换标准代码),比如小写字母‘a’的ascii 码是01100001,换算成十进制就是97,十六进制就是0x61。

但是随着互联网的发展,计算机传到中国,ASCII编码就行不通了,汉字这么这么多,一个字节肯定是表示不下的,至少需要两个字节甚至更多。于是中国就制定了GB2312编码(中国国家标准简体中文字符集),用于编码中文字符。GB2312中对所收汉字进行了“分区”处理,每区含有94个汉字/符号。这种表示方式也称为区位码。各区包含的字符如下:01-09区为特殊符号;

16-55区为一级汉字,按拼音排序;

56-87区为二级汉字,按部首/笔画排序;

10-15区及88-94区则未有编码。

GB2312使用两个字节来对一个字符进行编码,其中前面的一个字节(称之为高字节)从0xA1用到 0xF7【把01-87区的区号加上0xA0(16进制加法哦)】,后面一个字节(低字节)从0xA1到0xFE【把01-94加上0xA0】,GB2312能表示几千个汉字,而且也与ASCII码是兼容的。

全世界这么多国家,这么多种语言,大家都有一套自己的标准自己的编码,导致的结果就是在多种语言混合的文本中,不可避免的出现了“乱码”!!

这个时候,ISO(国际标准化组织)发明了”Universal Multiple-Octet Coded Character Set”,简称 UCS, 俗称 “unicode”。Unicode把所有语言都统一到一套编码里,这样就不会再有乱码问题了!但是!!unicode只是一个符号集,规定了符号的二进制代码【也就是说它给每一个字符一个独一无二的数字来表示。Unicode编码通常是2个字节(一个字符占用两个字节)】,而上面介绍的ASCII,GB2312,包括下面要说的utf-8,都属于编码方式。定义了一种将字符编码为字节码的方式。

字母 A 用ASCII编码是十进制的 65,二进制的01000001;

字母A用Unicode编码,只需要在前面补0就可以,A的Unicode编码是00000000 01000001。

汉字 中 已经超出了ASCII编码的范围,用Unicode编码是十进制的 20013,二进制的01001110 00101101。

很显然勤俭节约的小盆友很容易发现如果文本基本上全部是英文的话,用Unicode编码比ASCII编码需要多一倍的存储空间,在存储和传输上就十分不划算。

所以本着节约的精神,又出现了把Unicode编码转化为“可变长编码”的UTF-8编码。UTF-8编码把一个Unicode字符根据不同的数字大小编码成1-6个字节,常用的英文字母被编码成1个字节,汉字通常是3个字节,只有很生僻的字符才会被编码成4-6个字节。如果你要传输的文本包含大量英文字符,用UTF-8编码就能节省空间:

字符ASCIIUnicodeUTF-8

A0100000100000000 0100000101000001

中x01001110 0010110111100100 10111000 10101101

UTF-8的编码规则很简单,只有二条:

1)对于单字节的符号(英文字母/标点等),UTF-8编码和ASCII码是相同的。

2)对于n字节的符号(n>1),第一个字节的前n位都设为1,第n+1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的unicode码。

以上述汉字“中”为例:

从上面的表格还可以发现,UTF-8编码有一个额外的好处,就是ASCII编码实际上可以被看成是UTF-8编码的一部分,所以,大量只支持ASCII编码的历史遗留软件可以在UTF-8编码下继续工作。

编码&解码

总结一下现在计算机系统通用的字符编码工作方式:在计算机内存中,统一使用Unicode编码,当需要保存到硬盘或者需要传输的时候,就转换为UTF-8/gb312等编码。

用记事本编辑的时候,从文件读取的UTF-8字符被转换为Unicode字符到内存里,编辑完成后,保存的时候再把Unicode转换为UTF-8保存到文件。

上述的过程就涉及了两个概念:编码与解码编码(encode):将Unicode字符串转换为特定字符编码方式(ASCII、UTF-8、GB2312)对应的字节串的过程就是编码。【在Unicode中,每一个字符都有一个唯一的数字表示】【unicode-->str】

解码(decode):将特定字符编码方式(ASCII、UTF-8、GB2312)对应的字节串转换为对应的Unicode字符串的过程就是解码。【str-->unicode】

从计算机工作的方式来讲,编码的结果是给计算机底层用的,解码的结果是显示给人看的!

Python字符串

搞清楚了令人头疼的字符编码问题后,我们再来研究Python的字符串。

首先在执行python文件的时候,就有两个地方涉及到编码问题:

1.py源代码文本文件被保存之后是以某种特定编码的字节形式存放在磁盘上的,而这种字符编码方式是你在保存代码时,进行指定的,这里分位两部分:

a.  在文本编辑器中进行指定,比如:

b. 在py文件开头写上两行:

#!/usr/bin/env python3# -*- coding: utf-8 -*-

第一行注释是为了告诉Linux/OS X系统,这是一个Python可执行程序,Windows系统会忽略这个注释;

第二行注释是为了告诉Python解释器,按照UTF-8编码读取源代码,否则,你在源代码中写的中文输出可能会有乱码。

2.执行该py文件(python xx.py)时,Python解释器在读取py代码中的字符串之后,需要将其转换为Unicode字符串(decode过程),再执行后续操作。

默认编码

那么如果在步骤1,你并没有在写代码的时候指定编码方式,那Python解释器会使用哪种字符编码把从代码文件中读取到的字节转换为Unicode字符串呢?这么会使用“默认编码”

对于“默认编码”,这里首次出现了Python2与Python3的不同!!Python2和Python3的解释器使用的默认编码是不一样的,通过sys.getdefaultencoding()可以获取默认编码:

>>> # Python2>>> import sys>>> sys.getdefaultencoding()'ascii'>>> # Python3>>> import sys>>> sys.getdefaultencoding()'utf-8'

所以对于Python2来讲,Python解释器在读取到中文字符的字节码时,会先查看当前代码文件头部是否指明字符编码是什么。如果没有指定,则使用默认字符编码"ASCII"进行解码,这会导致中文字符解码失败,出现ERROR。

而Python3的解释器以"UTF-8"作为默认编码,但是这并不表示可以完全兼容中文问题。因为windows上默认终端编码是gbk,linux默认终端编码是utf-8。所以在windows上默认保存py代码文件时使用的是默认的gbk编码。这个时候Python3解释器执行该代码文件时,试图用UTF-8进行解码操作时同样会出现ERROR。

Python2 VS Python3Python 2

在python2.x中,有两种“字符串”类型,分别是str 与 unicode,他们有同一个基类basestring。str应该称之为字节串,因为是每一个字节换一个单位长度。而unicode才是真正的字符串,一个字符(可能多个字节)算一个单位长度。

class basestring(object)

class str(basestring)

class unicode(basestring)

所以在python 2.x中,unicode类型一定是unicode编码,而str类型可能是gbk、ascii或者utf-8编码。python2.7中,unicode类型需要在文本之间加u表示。

#!/usr/bin/env python#-*- coding:utf-8 -*-a = '中国' b = u'中国' print(type(a),len(a)) # output:(, 6)print(type(b),len(b)) # output:(, 2)

****需要注意的是:len(a)的长度在不同环境下是不一样的,上例因为指明了utf-8编码,所以一个汉字3个字节,两个汉字长度就是6

Python 3

而Python3中对字符串的支持进行了实现类层次的上简化,去掉了unicode类,添加了一个bytes类。从表面上来看,可认为Python3中的str和unicode合二为一了。

class bytes(object)

class str(object)

也就是说Python3开始明确区分字符串与字节串!!因此Python3中的str已经是真正的字符串,而字节是用单独的bytes类来表示

#!/usr/bin/env python#-*- coding:utf-8 -*-a = '中国' b = u'中国' c = '中国'.encode('utf-8') print(type(a),len(a)) # output: 2print(type(b),len(b)) # output: 2print(type(c),len(c)) # output: 6

总结一下。。

在Python3中的 str 对象在Python2中叫做 unicode 。但 bytes 对象在Python2中叫做 str ,对。。就是你平时用的 str , 嗯。默认的那个。。。

在python2中,如果你想得到一个文本字符串(注意不是字节串),你需要在字符串之前加上前缀 u 或者 decode 一下。

最无语的是,Python2中的 str (字节) 对象,竟然有一个 encode 方法。。。。而且不仅毫无用处,而且用了就报错,已经是字节码了还要怎么encode编码?!所以永远都别使用它!!! 同样的,unicode (文本字符) 对象也有一个用来报错的 decode 方法。

只用牢牢记住下面的流程图即可!!

decode    encode

str--------->unicode--------->str

我终于写完了我好累。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值