编码问题,一直是使用python2时的一块心病。几乎所有的控制台输入输出、IO操作和HTTP操作都会涉及如下的编码问题:
UnicodeDecodeError:‘ascii’codec can’t decodebyte0xc4inposition10:ordinalnotinrange(128)

这究竟是是个什么东西?!有时稀里糊涂地用一坨encode(),decode()之类的函数让程序能跑对了,可是下次遇到非ASCII编码时又悲剧了。

那么Python 2.x中的字符串究竟是个什么呢?

基本编码知识

在了解Python中字符串(String)的本质前,我们需要知道ASCII、GBK、UTF-8和Unicode的关系究竟几何。
我们知道,任何字符串都是一串二进制字节的序列,而ASCII码是最经典的编码方式,它将序列中的每个字节理解为一个字符,可表示阿拉伯数字、字母在内的128个不同字符。很明显,汉字在ascii中是无法表示的。
为了让计算机能够显示、处理汉字,勤劳朴实的中国人民制定了GBK(GB2312的扩展)编码,这是一种兼容ASCII的不定长(长度为1-2)编码,对于基本的128个字符仍旧用一个字节表示,但“翔”这样的中文就用两个字节表示:

UTF-8与GBK类似,也是一种兼容ASCII码的不定长编码形式,它的长度变化更大,因此可以表示几乎所有世界文字。具体细节可参考维基:http://zh.wikipedia.org/wiki/UTF-8

Unicode是一种定长的编码方式(同ASCII),不过它是每2字节认为是一个字符,如ASCII中0x61表示'a',在Unicode中用0x0061表示'a',它可映射所有文字,而且对于多种写法的字,如強/强,它都可以唯一地区分它们。

由于Unicode编码的字符串体积很大,因此一般来说Unicode编码只是文字在内存中的内在形式,具体的存储(如文件、网页等)都需要靠外在的编码(UTF-8、GBK等)诠释。

Python2.x中字符串的本质

Python中实际上有两种字符串,分别是str类型和unicode类型,这两者都是basestring的派生类。它们的区别如下:

字符串类型

常量子串表示

内存中表示

len()

len含义

str

S=“呵呵”

与源码文件完全一致,一坨二进制编码

若源码文件为UTF-8编码,
len(S)=6

字节数

unicode

S=u“呵呵”

Unicode编码

len(S)=2

字数

str类型的本质就是一坨二进制串,源文件(或获取的网页)的编码是怎样,它就跟着是怎样。实际上Python并不清楚某个str字符串到底是什么编码。这也就解释了为什么我们需要在python文件的开头标定该文件的编码是什么,如:

# encoding: utf-8

也解释了为什么len()一个str类型的字符串,只会返回它在内存中占用的字节数,而非文字数
相比于str,unicode是真正的字符串。Python明确地知道它的编码,所以可以很自信地获得一个字符串的实际字数。

字符串编码转换:encode()和decode()

Python最常用的编码转换函数是encode()和decode(),他们的本质是:unicode和str的互相转换
具体而言:
encode(encoding): 将unicode转换为str,并使用encoding编码;
decode(encoding):将str转换为unicode,其中str以encoding编码。

我们来看一个例子:

#encoding: utf-8s="你好"# 整个文件是UTF-8编码,所以这里的字符串也是UTF-8u=s.decode("utf-8")# 将utf-8的str转换为unicodeg=u.encode('GBK')# 将unicode转换为str,编码为GBKprinttype(s),"len=",len(s)# 输出:<type 'str'> len= 6,utf-8每个汉字占3字节printtype(u),"len=",len(u)# 输出:<type 'str'> len= 6,unicode统计的是字数printtype(g),"len=",len(g)# 输出:g = u.encode('GBK'),GBK每个汉字占2字节prints# 在GBK/ANSI环境下(如Windows),输出乱码,#因为此时屏幕输出会被强制理解为GBK;Linux下显示正常printg# 在Windows下输出“你好”,#Linux(UTF-8环境)下报错,原因同上。

在Windows7(中文)下运行结果如下:

<type'str'>len= 6<type'unicode'>len= 2<type'str'>len= 4
浣犲ソ
你好 Traceback (most recent call last):
File "C:/Users/Sunicy/Desktop/encode.py", line 15, in<module>g.decode('utf-8')
File "C:\Python27\lib\encodings\utf_8.py", line 16, in decode
return codecs.utf_8_decode(input, errors, True)
UnicodeDecodeError: 'utf8' codec can't decode byte 0xc4 in position 0: invalid continuation byte

判断变量是否为字符串

我们知道Python中判断一个变量是否为某个类型使用isinstance(变量, 类型)函数,如

isinstance(1.2,float)

返回值为True

那么判断变量是不是字符串能不能用

isinstance(s,str)

呢?

答案是否定的。
现在我们知道除了str之外,unicode类型也是字符串,因此上述代码如果遇到unicode字符串,就返回False。
直观地改进是既判断str又判断unicode:

isinstance(s,str)orisinstance(s,unicode)

不过这个方法有效,但是有点傻。既然str和unicode都派生自basestring,那么实际上以basestring作为类型是最稳妥的:

isinstance(s,basestring)

下面是一组例子:

isinstance("aaa",str)# -> Trueisinstance({},dict)# -> Trueisinstance([1,],list)# -> Trueisinstance("aaa",list)# -> Falseisinstance("你",str)# -> Falseisinstance("你好",basestring)# -> Trueisinstance("aaa",basestring)# -> True

总结

  1. unicode是支持所有文字的统一编码,但一般只用作文字的内部表示,文件、网页(也是文件)、屏幕输入输出等处均需使用具体的外在编码,如GBK、UTF-8等;
  2. encode和decode都是针对unicode进行“编码”和“解码”,所以encode是unicode->str的过程,decode是str->unicode的过程;
  3. unicode和str是一对孪生兄弟,来自basestring,所以用isinstance(s, basestring)来判断s是否为字符串。

Python中GBK, UTF-8和Unicode的编码问题的更多相关文章

  1. Python中import模块时报SyntaxError: (unicode error)utf-8 codec can not decode 错误的解决办法

    老猿有个通过UE编辑(其他文本编辑器一样有类似问题)的bmi.py文件,在Python Idle环境打开文件执行时没有问题,但import时报错: SyntaxError: (unicode erro ...

  2. python中的while循环,格式化输出,运算符,编码

    一.while循环 1.1语法 while 条件: 代码块(循环体) else: 当上面的条件为假的的时候,才会执行. 执行顺序:先判断条件是否为真,如果是真的,执行循环体,再次判断条件,直到条件不成 ...

  3. python 中的while循环、格式化、编码初始

    while循环 循环:不断重复着某件事就是循环 while 关键字 死循环:while True: ​ 循环体 while True: # 死循环# print("坚强")# pr ...

  4. Python中的数据类型、变量、字符编码、输入输出、注释

    数据类型 number(数字) 用于存储类型,通常分为int.long.float.complex: int:32位机器上占32位,取值范围为-231 ~ 231 - 1:64位机器上占64位,取值范 ...

  5. python中url解析 or url的base64编码

    目录 from urllib.parse import urlparse, quote, unquote, urlencode1.解析url的组成成分:urlparse(url)2.url的base6 ...

  6. python中迷茫的编码问题

    1.理清一些知识点: python默认的编码格式: ASCII(py2) unicode(py3) 查看默认编码:sys.defaultencoding 修改默认编码:#coding = utf-8 ...

  7. 《python解释器源码剖析》第3章--python中的str对象

    3.0 序 我们知道python中的字符串属于变长对象,当然和int也是一样,底层的结构体实例所维护的数据的长度,在对象没有定义的时候是不知道的.当然如果是python2的话,底层PyIntObjec ...

  8. python中unicode、utf8、gbk等编码问题

    转自:http://luchanghong.com/python/2012/07/06/python-encoding-with-unicode-and-gbk-and-utf8.html 概要:编码 ...

  9. python 中的unicode详解

    通过例子来看问题是比较容易懂的. 首先来看,下面这个是我新建的一个txt文件,名字叫做ivan_utf8.txt,然后里面随便编辑了一些东西. 然后来用控制台打开这个文件,同样也是截图: 这里就是简单 ...

随机推荐

  1. Django跨域解决方法

    from django.utils.deprecation import MiddlewareMixin class Mymiddle(MiddlewareMixin): def process_re ...

  2. 【AAA】AAA协议介绍

    AAA AAA简介 AAA是认证(Authentication).授权(Authorization)和计费(Accounting)的简称,是网络安全中进行访问控制的一种安全管理机制,提供认证.授权和计 ...

  3. js验证营业执照号码是否合规

    需求:最近要做实名验证的功能,但是验证我们要验证严谨一点,参考了网上关于营业执照号码规则和一些大侠的代码的代码,总结一下. 营业执照号码规则:规则 代码: //方法一:function checkLi ...

  4. 一分钟认识:Cucumber框架

    一分钟认识:Cucumber框架(一) 转自:https://www.cnblogs.com/dami520/p/3168864.html 个人感觉这个框架非常适合UI自动化测试,他不仅能把用例中的测 ...

  5. (Forward)5 Public Speaking Tips That'll Prepare You for Any Interview

    Landing a job interview is incredibly exciting –- and often terrifying. But fear not. There are clev ...

  6. 8、导航:Nav

    1.导航视图   angular2 中的是视图是显示在<router-outlet></router-outlet>里的同时他要依赖于 directives:[ ROUTER_ ...

  7. nodejs常用npm包

    express常用npm包整理如下 art-template 一款js模板引擎,性能不错 jayson     一款纯node的rpc应用包,可实现rpc服务.tcp.http等服务 multer   ...

  8. Spring Cloud实战之初级入门(四)— 利用Hystrix实现服务熔断与服务监控

    目录 1.环境介绍 2.服务监控 2.1 加入依赖 2.2 修改配置文件 2.3 修改启动文件 2.4 监控服务 2.5 小结 3. 利用hystrix实现消费服务熔断 3.1 加入服务熔断 3.2 ...

  9. linux 安装php扩展swoole redis

    本文讲的是已经有redis.so 和swoole.so文件的情况 我的环境是xampp php的扩展目录为 /opt/lampp/lib/php/extensions/no-debug-non-zts ...

  10. CSS实现微信对话框