当前位置:首页>编程日记>正文

python2 python3编码_Python2和Python3编码问题-从底层出发

本站寻求有缘人接手,详细了解请联系站长QQ1493399855

首先需要强调---无论是python2还是python3都可以理解成是Unicode编码,但是在电脑硬盘上存储是按照不同的映射关系的。

Python的encode和decode 首先明白一件事情,之前说过Unicode将所有的字符都对应上了相应的码点,而UTF-8或者ASCII码不过是对应从Unicode到字节的映射方式,既然有映射方式,那么就有映射方向。

我们把从Unicode到字节码(byte string)称之为encode,把从字节码(byte string)到Unicode码称之为decode

Python2

1.编码转换

编码转换时,通常需要以unicode作为中间编码,即先将其他编码的字符串解码(decode)成unicode,再从unicode编码(encode)成另一种编码。

python2 python3编码_Python2和Python3编码问题-从底层出发 配图01

2.存储方式

python2中,有两种不同的字符串数据类型,

一种是 “str”对象,字节存储,

如果在字符串前使用一个’u’的前缀,表示的是这个字符的Unicode码点

详细说明

1. Python2 处理英文字符

>>> str='hello' #首先’hello'字符串的每个英文字符变换成unicode编码;在存储时python2对英文按照ascii射的方式编码存储5个字节编码

>>> str

'hello'

>>> type(str) #此时赋值给str,就是第一种: “str”对象,存储着字节

>>> len(str) #len字符数,就是一字节一英文字符

5

>>> str.decode('ascii') #'ascii'解码:按照ascii规则吧str英文字符由字节编码映射成字符编码,也就是把str对象类型变为unicode字符码

u'hello'

>>> str.decode('uTf-8') #'utf-8'解码:按照utf-8规则吧str英文字符由字节编码映射成字符编码,也就是把str对象类型变为unicode字符码

#结果为什么结果一样,因为对待英文字符AscII和utf-8都是按照一个字节存储的, 没有什么差别

>>> print(u'hello') #关于print 函数,无论字符unicode编码还是字节ascii编码都能正常输出

hello

>>> print(str)

2.Python2处理中文字符

直接输入

>>> str="中国" #中文在python2中是按照gbk编码的;

>>> type(str)

>>> str #str仍然是一个str对象(字节存储)

'xd6xd0xb9xfa'

>>> len(str) #len函数处理str对象,是统计str字节的个数;因为str是字节编码的

4

以下是对str对象的解码操作;不难发现中文在python2中是按照gbk编码的

>>> str.decode('ascii') #'ascii'解码报错

Traceback (most recent call last):

File "", line 1, in

str.decode('ascii')

UnicodeDecodeError: 'ascii' codec can't decode byte 0xd6 in position 0: ordinal not in range(128)

>>> str.decode('utf-8') #'utf-8'解码报错

str.decode('utf-8')

File "C:Python27libencodingsutf_8.py", line 16, in decode

return codecs.utf_8_decode(input, errors, True)

UnicodeDecodeError: 'utf8' codec can't decode byte 0xd6 in position 0: invalid continuation byte

>>> str.decode('gbk') #'gbk'解码成功

u'u4e2du56fd'

>>> str1= str.decode('gbk') #str(gbk)字节编码 解码为 unicode字符编码 存到str1

>>> str1.encode('ascii') #str1 (unicode字符编码) 按照'ascii'编码 出错

#显然:ascii编码并不能处理unicode编码的中文,所以出错

str1.encode('ascii')

UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)

对于unicode编码的中文在python2中是按可以用'gbk','utf-8'编码的,但是不能被'ascii'编码

>>> str1.encode('gbk') #'gbk'编码

>>> str1.encode('utf-8') #'utf-8'编码

'xe4xb8xadxe5x9bxbd'

print输出语句:再次证明:无论是unicode还是utf-8,gbk的字节编码都可以很好的输出

>>> print(u'u4e2du56fd')

中国

>>> print('xd6xd0xb9xfa')

>>> print('xe4xb8xadxe5x9bxbd')

>>> str3=str1.encode('utf-8') #又一次证明:len函数对于字节编码,按照字节算个数

>>> len(str3)

6

u'字符串输入'

>>> str=u'中国'

>>> len(str)

2

又一次证明:len函数对于unicode编码,按照字符个数算

所以,对于python2,强烈建议在输入字符串加个u,按照unicode编码存储。

3. Python2程序开头写#coding=utf-8的作用

Python文件编译最终还是要转换成字节码,Python2程序开头写#coding=utf-8的作用其实就是把这个Python程序文件按照utf-8编码的方式映射到字节码,如果不加这个开头,程序里面的中文会按照Python默认的ascii码方式encode,这个肯定是要报错的,大家都知道,如果程序里写了中文但是没有加这个开头,那么pycharm会在一开始就报错,也是这个道理。加了这个开头之后,程序里面的字符都将会使用utf-8编码的方式被映射到字节码,也就是上一个大节里面的byte string,值得注意的是,程序中的汉字将会以utf-8的形式编码成为字节码,因此如果需要将其decode到Unicode字符,也是需要使用utf-8方式decode。

4.中文编码处理--补充

1.python2因为ascii对中文(unicode)编码解码错误

(1)错误写法:

原因:开头并没有改变Python的系统编码方式:Python2默认的编码解码方式是ascii码

s='中国'

s_decode=s.decode('utf-8')

ps=s_decode+s #字节编码与字符编码拼接最后是 字符编码;所以s字节编码需要解码,这时按照ascii码

print ps # 中文不能被'ascii'解码编码 ,出错

ps=s_decode+s

UnicodeDecodeError: 'ascii' codec can't decode byte 0xe4 in position 0: ordinal not in range(128)

(2)解决办法:正确写法

>>> import sys

>>> reload(sys)

>>> sys.setdefaultencoding('utf-8')

>>> s_decode+s

u'u4e2du56fdu4e2du56fd'

这个代码将Python的编码默认编码方式由ascii码换成了utf-8编码,因此s_decode+s这个就不像上面一样报错了。

或则显示指明:

#coding=utf-8

ps=s_decode+s.decode('utf-8')

print ps

python test.py

中国中国

Python3

在python3 中 Python 3 也有两种类型,一个是 str(unicode), 一个是 byte 码。但是它们有不同的命名。

Python 3 中对 Unicode 支持的最大变化就是没有对 byte 字符串的自动解码。

如果你想要用一个 byte 字符串和一个 unicode 相连接的话,你会得到一个错误,不管包含的内容是什么。 可以简单理解为: python2 中的unicode -> python3 的str python2 中的str-> python3 的byte

py3里,只有 unicode编码格式 的字节串才能叫作str, 其他编码格式的统统都叫bytes,如:gbk,utf-8,gb2312…………

在py3中,Unicode编码就像是一个枢纽,例如gbk的格式要想转化成utf-8,那么必须先转化成Unicode,然后再从Unicode转化成utf-8

1. python3处理中文

>>> s="中"

>>> type(s)

>>> s

'中'

>>> len(s) #s是unicode编码 字符编码

1

>>> s.encode('utf-8')

b'xe4xb8xad'

'''任何中文的unicod编码,都不能用ascii编码/解码'''

>>> s.encode('ascii')

s.encode('ascii')

UnicodeEncodeError: 'ascii' codec can't encode character 'u4e2d' in position 0: ordinal not in range(128)

>>> s1=s.encode('utf-8')

>>> s1

>>> type(s1)

>>> s1.decode('utf-8') #只要是unicode(str对象)就可以直接输出

'''对于byte.decode()解码:python3不支持二进制形式解码,python2支持'''

#python3

>>>'xe4xb8xad'.decode('utf-8')

'xe4xb8xad'.decode('utf-8')

AttributeError: 'str' object has no attribute 'decode'

#python2

>>> 'xe4xb8xad'.decode('utf-8')

u'u4e2d'

2. python3处理英文字符

>>> s='dv'

'dv'

>>> len(s)

b'dv'

>>> s1= s.encode('utf-8')

>>> s2=s+s1

s2=s+s1

TypeError: can only concatenate str (not "bytes") to str

>>> s3=s+s1.decode('utf-8')

>>> s3

'dvdv'

3.文件操作

文件读写:open还是 codecs.open?

python读写文件估计大家都用open内置函数,但是用open方法打开会有一些问题。open打开文件只能写入str类型,不管字符串是什么编码方式。例如

>>> fr = open('test.txt','a')

>>> line1 = "我爱祖国"

>>> fr.write(line1)

这样是完全可以的。但是有时候我们爬虫或者其他方式得到一些数据写入文件时会有编码不统一的问题,所以就一般都统一转换为unicode。此时写入open方式打开的文件就有问题了。例如

>>> line2 = u'我爱祖国'

>>> fr.write(line2)

fr.write(line2)

UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-11: ordinal not in range(128)

怎么办,我们可以将上面的line2编码成str类型,但是太麻烦。我们要把得到的东西先decode为unicode再encode为str。。。

input文件(gbk, utf-8...) ----decode-----> unicode -------encode------> output文件(gbk, utf-8...)

代替这繁琐的操作就是codecs.open,例如

>>> import codecs

>>> fw = codecs.open('test1.txt','a','utf-8')

>>> fw.write(line2)

>>>

不会报错,说明写入成功。这种方法可以指定一个编码打开文件,使用这个方法打开的文件读取返回的将是unicode。写入时,如果参数 是unicode,则使用open()时指定的编码进行编码后写入;如果是str,则先根据源代码文件声明的字符编码,解码成unicode后再进行前述 操作。相对内置的open()来说,这个方法比较不容易在编码上出现问题。

还是文件读写操作

上文中介绍的codecs.open()方法虽然明显比open要方便好用很多,但是使用这个函数的前提是我们需要知道文件的编码方式,但是事实是我们大多数情况下不知道文件的编码方式,所以一下给出两种解决办法。

1.最原始的方法。

ways = ["utf-8","gbk","gb2312","ASCII","Unicode"]

for encoding in ways:

print(encoding)

try:

with codecs.open("test.csv","r",encoding=encoding) as f:

data = f.read()

print(type(data))

break

except Exception as e:

pass

将python中常用的编码方式用list表示,然后用for循环逐一带入检验。由于utf-8和gbk用的较多,所以建议放在list的最前面。

一旦文件操作成功,则break,跳出循环。

2.比较高端的方法

可以以bytes的形式对文件进行操作,这样即使不知道文件的编码方式也同样可以进行读写操作了,但是在最后需要进行decode或者encode。

如果对decode和encode不了解,请阅读这篇文章python编码问题之"encode"&"decode"

with codecs.open("test.csv","rb") as f:

encodeInfo = chardet.detect(data)

print(data.decode(encodeInfo["encoding"]))

参考文章:

欢迎各位大佬指正!


http://www.coolblog.cn/news/fb8a7c9e6ce6128d.html

相关文章:

  • asp多表查询并显示_SpringBoot系列(五):SpringBoot整合Mybatis实现多表关联查询
  • s7day2学习记录
  • 【求锤得锤的故事】Redis锁从面试连环炮聊到神仙打架。
  • 矿Spring入门Demo
  • 拼音怎么写_老师:不会写的字用圈代替,看到孩子试卷,网友:人才
  • Linux 实时流量监测(iptraf中文图解)
  • Win10 + Python + GPU版MXNet + VS2015 + RTools + R配置
  • 美颜
  • shell访问php文件夹,Shell获取某目录下所有文件夹的名称
  • 如何优雅的实现 Spring Boot 接口参数加密解密?
  • LeCun亲授的深度学习入门课:从飞行器的发明到卷积神经网络
  • Mac原生Terminal快速登录ssh
  • 法拉利虚拟学院2010 服务器,法拉利虚拟学院2010
  • 支撑微博千亿调用的轻量级RPC框架:Motan
  • mysql commit 机制_1024MySQL事物提交机制
  • java受保护的数据与_Javascript类定义语法,私有成员、受保护成员、静态成员等介绍...
  • 2019-9
  • jquery 使用小技巧
  • 科学计算工具NumPy(3):ndarray的元素处理
  • vscode pylint 错误_将实际未错误的py库添加到pylint白名单
  • 工程师在工作电脑存 64G 不雅文件,被公司开除后索赔 41 万,结果…
  • linux批量创建用户和密码
  • js常用阻止冒泡事件
  • 气泡图在开源监控工具中的应用效果
  • newinsets用法java_Java XYPlot.setInsets方法代碼示例
  • 各类型土地利用图例_划重点!国土空间总体规划——土地利用
  • php 启动服务器监听
  • dubbo简单示例
  • Ubuntu13.10:[3]如何开启SSH SERVER服务
  • [iptables]Redhat 7.2下使用iptables实现NAT
  • Django View(视图系统)
  • 【设计模式】 模式PK:策略模式VS状态模式
  • CSS小技巧——CSS滚动条美化
  • JS实现-页面数据无限加载
  • 最新DOS大全
  • 阿里巴巴分布式服务框架 Dubbo
  • 阿里大鱼.net core 发送短信
  • Sorenson Capital:值得投资的 5 种 AI 技术
  • 程序员入错行怎么办?
  • Arm芯片的新革命在缓缓上演
  • 两张超级大表join优化
  • 第九天函数
  • Linux软件安装-----apache安装
  • HDU 5988 最小费用流
  • 《看透springmvc源码分析与实践》读书笔记一
  • 通过Spark进行ALS离线和Stream实时推荐
  • nagios自写插件—check_file
  • python3 错误 Max retries exceeded with url 解决方法
  • 正式开课!如何学习相机模型与标定?(单目+双目+鱼眼+深度相机)
  • 行为模式之Template Method模式