Python中GBK, UTF-8和Unicode的编码问题
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编码, |
字节数 |
|
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
总结
- unicode是支持所有文字的统一编码,但一般只用作文字的内部表示,文件、网页(也是文件)、屏幕输入输出等处均需使用具体的外在编码,如GBK、UTF-8等;
- encode和decode都是针对unicode进行“编码”和“解码”,所以encode是unicode->str的过程,decode是str->unicode的过程;
- unicode和str是一对孪生兄弟,来自basestring,所以用isinstance(s, basestring)来判断s是否为字符串。
Python中GBK, UTF-8和Unicode的编码问题的更多相关文章
- Python中import模块时报SyntaxError: (unicode error)utf-8 codec can not decode 错误的解决办法
老猿有个通过UE编辑(其他文本编辑器一样有类似问题)的bmi.py文件,在Python Idle环境打开文件执行时没有问题,但import时报错: SyntaxError: (unicode erro ...
- python中的while循环,格式化输出,运算符,编码
一.while循环 1.1语法 while 条件: 代码块(循环体) else: 当上面的条件为假的的时候,才会执行. 执行顺序:先判断条件是否为真,如果是真的,执行循环体,再次判断条件,直到条件不成 ...
- python 中的while循环、格式化、编码初始
while循环 循环:不断重复着某件事就是循环 while 关键字 死循环:while True: 循环体 while True: # 死循环# print("坚强")# pr ...
- Python中的数据类型、变量、字符编码、输入输出、注释
数据类型 number(数字) 用于存储类型,通常分为int.long.float.complex: int:32位机器上占32位,取值范围为-231 ~ 231 - 1:64位机器上占64位,取值范 ...
- python中url解析 or url的base64编码
目录 from urllib.parse import urlparse, quote, unquote, urlencode1.解析url的组成成分:urlparse(url)2.url的base6 ...
- python中迷茫的编码问题
1.理清一些知识点: python默认的编码格式: ASCII(py2) unicode(py3) 查看默认编码:sys.defaultencoding 修改默认编码:#coding = utf-8 ...
- 《python解释器源码剖析》第3章--python中的str对象
3.0 序 我们知道python中的字符串属于变长对象,当然和int也是一样,底层的结构体实例所维护的数据的长度,在对象没有定义的时候是不知道的.当然如果是python2的话,底层PyIntObjec ...
- python中unicode、utf8、gbk等编码问题
转自:http://luchanghong.com/python/2012/07/06/python-encoding-with-unicode-and-gbk-and-utf8.html 概要:编码 ...
- python 中的unicode详解
通过例子来看问题是比较容易懂的. 首先来看,下面这个是我新建的一个txt文件,名字叫做ivan_utf8.txt,然后里面随便编辑了一些东西. 然后来用控制台打开这个文件,同样也是截图: 这里就是简单 ...
随机推荐
- PyCharm | 常见问题
1.安装使用 每次建立PyCharm工程都建立一个虚拟环境env,需要重新下载或复制模块
- 宜人贷项目里-----正则匹配input输入月份规则
在标签上可以直接进行校验如下,如果只调数字键盘type=number不好用可以用type=tel <input name="creditDate" oninput=" ...
- 正则表达式控制Input输入内容 ,js正则验证方法大全
https://blog.csdn.net/xushichang/article/details/4041507 //输入姓名的正则校验 e.currentTarget.value = e.curre ...
- 关于display:none;和id特性的一些需要注意的地方
关注点一: display:none;一旦用于某个元素,那个这个元素在页面中就不再占据位置. visibility:hidden;用于某个元素时,这个元素还会占据位置. 关注点二: 即使使用了disp ...
- Oracle 数据库名、实例名、Oracle_SID
本文参考自ORACLE 数据库名.实例名.ORACLE_SID的区别,纯属读书笔记,加深记忆 在ORACLE7.8数据库中只有数据库名(db_name)和数据库实例名(instance_name).在 ...
- 使用spring遇到问题 事物不提交和更新失败
1 使用学习使用spring mvc进行前端代码编写,发现提交修改没发sql语句 测试dao层又没问题 解决: 原来是spring配置文件,事物管理 绑定到了dao层.测试界面前端应该绑定到servi ...
- ubuntu 64上的GCC如何编译32位程序
运行命令 gcc -v 显示: Target: x86_64-linux-gnu 所以,我这里的gcc默认生成64位的程序. 如果想编出32位的程序,就要加 -m32选项.可是我尝试了,还是不行. 原 ...
- UEditor编辑器 字符数统计和字符数限制 问题
1.百度UEditor修改右下角统计字数默认只统计前台所见的文字个数,为了便于展示实际保存的时候是保存的包含html标签的,所以右下角的统计字数功能需要修改 getContentLength: fun ...
- requirejs和seajs使用感受
这几天看了下前端模块化的知识,主要是requirejs和seajs相关的知识,还未看es6的模块化知识. 由于目前项目组内的开始推广使用vue,并且开始简单的封装组件,但发现组件js的使用方式依然是原 ...
- JMS - ActiveMQ的简单使用
首先需要下载ActiveMQ,下面的链接给我们列出了所有版本:http://activemq.apache.org/download-archives.html每个版本为不同的OS提供了链接: 公司电 ...