关于python 字符串编码一直没有搞清楚,今天总结了一下。

Python 字符串类型

Python有两种字符串类型:str 与 unicode。

字符串实例

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

# 这个是 str 的字符串
s = '关关雎鸠' # 这个是 unicode 的字符串
u = u'关关雎鸠' print isinstance(s, str) # True
print isinstance(u, unicode) # True print s.__class__ # <type 'str'>
print u.__class__ # <type 'unicode'>

前面的申明表明,上面的 Python 源代码由 utf-8 编码,由于代码中有中文,所以需要加上。

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

两种python字符串类型之间的转换

# 从 str 转换成 unicode
print s.decode('utf-8') # 关关雎鸠 # 从 unicode 转换成 str
print u.encode('utf-8') # 关关雎鸠

为什么从 unicode 转 str 是 encode,而反过来叫 decode?

因为 Python 认为 16 位的 unicode 才是字符的唯一内码,而大家常用的字符集如 gb2312,gb18030/gbk,utf-8,以及 ascii 都是字符的二进制(字节)编码形式。把字符从 unicode 转换成二进制编码,当然是要 encode。

反过来,在 Python 中出现的 str 都是用字符集编码的 ansi 字符串。Python 本身并不知道 str 的编码,需要由开发者指定正确的字符集 decode。

如果用错误的字符集来 encode/decode 会怎样?

# 用 ascii 编码含中文的 unicode 字符串
u.encode('ascii') # 错误,因为中文无法用 ascii 字符集编码
# UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-3: ordinal not in range(128) # 用 gbk 编码含中文的 unicode 字符串
u.encode('gbk') # 正确,因为 '关关雎鸠' 可以用中文 gbk 字符集表示
# '\xb9\xd8\xb9\xd8\xf6\xc2\xf0\xaf'
# 直接 print 上面的 str 会显示乱码,修改环境变量为 zh_CN.GBK 可以看到结果是对的 # 用 ascii 解码 utf-8 字符串
s.decode('ascii') # 错误,中文 utf-8 字符无法用 ascii 解码
# UnicodeDecodeError: 'ascii' codec can't decode byte 0xe5 in position 0: ordinal not in range(128) # 用 gbk 解码 utf-8 字符串
s.decode('gbk') # 不出错,但是用 gbk 解码 utf-8 字符流的结果,显然只是乱码
# u'\u934f\u51b2\u53e7\u95c6\u5ea8\u7b2d'

陷阱

这要提到处理 Python 编码时容易遇到的陷阱。

字符串连接


# -*- coding: utf-8 -*-
# file: example2.py # 这个是 str 的字符串
s = '关关雎鸠' # 这个是 unicode 的字符串
u = u'关关雎鸠' s + u # 失败,UnicodeDecodeError: 'ascii' codec can't decode byte 0xe5 in position 0: ordinal not in range(128)

在进行同时包含 str 与 unicode 的运算时,Python 一律都把 str 转换成 unicode 再运算,当然,运算结果也都是 unicode。

由于 Python 事先并不知道 str 的编码,它只能使用 sys.getdefaultencoding() 编码去 decode。sys.getdefaultencoding() 的值一般是 'ascii'。

显然,如果需要转换的 str 有中文,一定会出现错误。

% 运算的结果

# 正确,所有的字符串都是 str, 不需要 decode
"中文:%s" % s # 中文:关关雎鸠 # 失败,相当于运行:"中文:%s".decode('ascii') % u
"中文:%s" % u # UnicodeDecodeError: 'ascii' codec can't decode byte 0xe5 in position 0: ordinal not in range(128) # 正确,所有字符串都是 unicode, 不需要 decode
u"中文:%s" % u # 中文:关关雎鸠 # 失败,相当于运行:u"中文:%s" % s.decode('ascii')
u"中文:%s" % s # UnicodeDecodeError: 'ascii' codec can't decode byte 0xe5 in position 0: ordinal not in range(128)

在 Python 3 已经取消了 str,让所有的字符串都是 unicode ——这也许是个正确的决定。

总结

string 模块已经停止了更新,只保留了 ASCII 码的支持,string 模块已经不推荐使用,在任何需要跟 Unicode 兼容的代码里都不要再用该模块,Python 保留该模块仅仅是为了向后兼容.

Python 把硬编码的字符串叫做字面上的字符串,默认所有字面上的字符串都用 ASCII 编码,可以通过在字符串前面加一 个'u'前缀的方式声明 Unicode 字符串,这个'u'前缀告诉 Python 后面的字符串要编码成 Unicode 字符串 .

内建的 str()函数和 chr()函数并没有升级成可以处理 Unicode.它们只能处理常规的 ASCII 编码字符串,如果一个 Unicode 字符串被作作为参数传给了 str()函数,它会首先被转换 成 ASCII 字符串然后在交给 str()函数.

如果该 Unicode 字符串中包含任何不被 ASCII 字符串支 持的字符,会导致 str()函数报异常.同样地,chr()函数只能以 0 到 255 作为参数工作.如果你 传给它一个超出此范围的值(比如说一个 Unicode 字符),它会报异常.

新的内建函数 unicode()和 unichar()可以看成 Unicode 版本的 str()和 chr().Unicode() 函数可以把任何 Python 的数据类型转换成一个 Unicode 字符串,如果是对象,并且该对象定义 了__unicode__()方法,它还可以把该对象转换成相应的 Unicode 字符串.

处理字符串的准则:

  • 程序中出现字符串时一定要加个前缀u.
  • 不要用str()函数,用unicode()代替.
  • 不要用过时的 string 模块 -- 如果传给它的是非 ASCII 字符,它会把一切搞砸。
  • 不到必须时不要在你的程序里面编解码 Unicod 字符.只在你要写入文件或数据库或者网络时,才调用 encode()函数;相应地,只在你需要把数据读回来的时候才调用 decode() 函数.

参考

http://in355hz.iteye.com/blog/1860787

《python核心编程 第二版》

python编码encode decode(解惑)的更多相关文章

  1. python编码encode和decode

    计算机里面,编码方法有很多种,英文的一般用ascii,而中文有unicode,utf-8,gbk,utf-16等等. unicode是 utf-8,gbk,utf-16这些的父编码,这些子编码都能转换 ...

  2. python编码问题 decode与encode

    参考: http://www.jb51.net/article/17560.htm 如果要在python2的py文件里面写中文,则必须要添加一行声明文件编码的注释,否则python2会默认使用ASCI ...

  3. Python编码(encode)和解码(Decode)常见的两个错误

    项目地址:https://git.io/pytips 0x07 和 0x08 分别介绍了 Python 中的字符串类型(str)和字节类型(byte),以及 Python 编码中最常见也是最顽固的两个 ...

  4. [Python函数]encode,decode

    前言: 我们知道,计算机是以二进制为单位的,也就是说计算机只识别0和1,也就是我们平时在电脑上看到的文字,只有先变成0和1,计算机才会识别它的意思.这种数据和二进制的转换规则就是编码.计算机的发展中, ...

  5. is 和 == 区别,id() ,回顾编码,encode(),decode()

    1. is 和 == 区别 id()函数 == 判断两边的值 is 判断内存地址例 s = "alex 是 大 xx"# abc = id(s) # 得到内存地址# print(a ...

  6. 字符编码和python使用encode,decode转换utf-8, gbk, gb2312

    ASCII码 标准ASCII码使用7位二进制数表示大写或小写字母,数字0到9标点符号以及在美式英语中使用的特殊控制字符. 在标准ASCII码中,最高位(b7)用作奇偶校验位,所谓奇偶校验,是指在代码传 ...

  7. Python 编码encode()、 解码decode()问题

    乱码这种东西,时不时出现.本来开开心心想着我要学习啦,然后兴高采烈打开了比火星文还火星文的字符-- 没事,我可以搞定这堆鬼画符. 先来讲一下为什么有乱码这种东西的存在 故事是这样滴: 字符串是Pyth ...

  8. 太白老师 day06 编码 encode decode

    ASCII : 字母, 数字, 特殊字符 字符:1个字节 数字: 1个字节 Unicode: 万国码, 包含所有文字 创建之初 字符: 2个字节 中文: 2个字节 升级: 字符: 4个字节 中文 : ...

  9. Python编码介绍——encode和decode

    在 python 源代码文件中,如果你有用到非ASCII字符,则需要在文件头部进行字符编码的声明,声明如下: # code: UTF-8 因为python 只检查 #.coding 和编码字符串,所以 ...

随机推荐

  1. vue 首屏渲染优化 -- 这个不错

    这篇文章分享了从遇到前端业务性能问题,到分析.解决并且梳理出通用的Vue 2.x 组件级懒加载解决方案(Vue Lazy Component )的过程. 初始加载资源过多 问题起源于我们的一个页面,下 ...

  2. tp5 Excel导出

    1.百度搜索 PHPexcel (这是一个PHP类库) 2.下载的文件放到vendor里(这是tp5专门放置类库文件的) 下面是代码 /** * 导出 */ public function expor ...

  3. 绕过Snoopy的记录功能

    不讲原理,感兴趣请看http://blog.rchapman.org/posts/Bypassing_snoopy_logging/,这个只适合老版本内核的Linux 查看是否有snoopy加载了 l ...

  4. HTTPS双向认证+USB硬件加密锁(加密狗)配置

    环境:  Ubuntu14.04,apache2.4.7, openssl1.0.1f 安装apache2 apt-get install apache2 -y 一般openssl默认已经安装 开启a ...

  5. APP注册&登陆 逻辑细节

    前言:有多少用户愿意注册登陆,决定了一款产品的最大活跃度. 用户登陆注册系统分为两大类: 自建用户系统:邮箱/手机号/用户名/二维码/人脸识别/指纹 第三方授权用户系统:微信/微博/支付包/豆瓣/Fa ...

  6. 如何用DAX实现查看每个月中不同类别排名前一位,以及一个简单的svg案例

    现在给大家带来的是如何用DAX实现查看每个月中不同类别的排名前一位,最终完成效果如下!!! 首先我们需要两张简单的表 基数表 和类别表 当我们创建好表之后,我们再创建一个表格,然后我们将类别表里的列值 ...

  7. IPFS的配置安装

    目录 1. IPFS简介 2. IPFS本地环境安装 2.1 下载ipfs压缩包 2.2 安装 3. 项目配置 3.1 创建ipfs节点 3.2 修改节点默认存储空间 3.3 查看节点id 3.4 启 ...

  8. 从图像中检测和识别表格,北航&微软提出新型数据集 TableBank

    纯学术 的识别表格的文章: http://hrb-br.com/5007404/20190321A0B99Y00.html https://github.com/doc-analysis/TableB ...

  9. PHP 设计模式系列 —— 工厂方法模式(Factory Method)(转)

    1.模式定义 定义一个创建对象的接口,但是让子类去实例化具体类.工厂方法模式让类的实例化延迟到子类中. 2.问题引出 框架需要为多个应用提供标准化的架构模型,同时也要允许独立应用定义自己的域对象并对其 ...

  10. 使用rsync, 向另外一台服务器同步目录和文件的脚本

    #!/bin/bash #亚特兰蒂斯-同步目录#定时任务ini_file="/usr/local/sunlight/conf/rsync-file.ini"target_ip=&q ...