还是关于编码——decode & encode的探究

最近被py3.4中的编码折磨的不要不要的,decode & encode的使用、功能貌似在2.7—3.0有一个巨大的变化。网上查询的一些解答很多是基于2.7中的unicode功能,给出的解答是下面:
decode(解码)的作用是将其他编码的字符串转换成unicode编码,如str1.decode('gb2312'),表示将gb2312编码的字符串转换成unicode编码。
encode(编码)的作用是将unicode编码转换成其他编码的字符串,如str2.encode('gb2312'),表示将unicode编码的字符串转换成gb2312编码。



但自己实践起来完全不是那样,可以说错误百出。最基本的:decode & encode不在是”unicode→其他编码的解码、编码”过程,而是Str→bytes的解码、编码。在这里,还要对Str和bytes做本质性的深入探究
(以下资料都是网上查到的,问题很多,最主要的是不成体系,有些人这样理解,有些人那样理解,也许他们都能成熟使用py3.4编码,但对初学者就很不友好了,很多名词的定义和解释也不一致,我只能尽自己努力去整合)
<此段文字时间是2009,应该是基于py2.0>
字符串在Python内部的表示是unicode编码,因此,在做编码转换时,通常需要以unicode作为中间编码,即先将其他编码的字符串解码(decode)成unicode,再从unicode编码(encode)成另一种编码。 

decode的作用是将其他编码的字符串转换成unicode编码,如str1.decode('gb2312'),表示将gb2312编码的字符串str1转换成unicode编码。 

encode的作用是将unicode编码转换成其他编码的字符串,如str2.encode('gb2312'),表示将unicode编码的字符串str2转换成gb2312编码。 

因此,转码的时候一定要先搞明白,字符串str是什么编码,然后decode成unicode,然后再encode成其他编码


代码中字符串的默认编码与代码文件本身的编码一致。 

如:s='中文'

如果是在utf8的文件中,该字符串就是utf8编码,如果是在gb2312的文件中,则其编码为gb2312。这种情况下,要进行编码转换,都需要先用decode方法将其转换成unicode编码,再使用encode方法将其转换成其他编码。通常,在没有指定特定的编码方式时,都是使用的系统默认编码创建的代码文件。 

如果字符串是这样定义:s=u'中文'

则该字符串的编码就被指定为unicode了,即python的内部编码,而与代码文件本身的编码无关。因此,对于这种情况做编码转换,只需要直接使用encode方法将其转换成指定编码即可。


如果一个字符串已经是unicode了,再进行解码则将出错,因此通常要对其编码方式是否为unicode进行判断:

isinstance(s, unicode)  #用来判断是否为unicode 

用非unicode编码形式的str来encode会报错 

以上文字可以说已经完全被py3.0抛弃了,我是从3.0入手的,那么怎么办呢? 功夫不负有心人,终于在某论坛里找到了类似问题。

1 #python 3中只有unicode str,所以把decode方法去掉了。已经是unicode的str,不用decode。如果文件内容不是unicode编码的,要先以二进制方式打开,读入比特流,再解码码。

 

2.#python语言中有两种不同的字符串,一个用于存储文本,一个用于存储原始字节。 文本字符串内部使用Unicode存储,字节字符串存储原始字节并显示ASCII。(无法显示为ASCII字符的字节,用\x##显示。)

python3中,文本型字符串类型 被命名为 str,字节字符串类型 被命名为 bytes。 正常情况下,实例化一个字符串会得到一个str实例,如果希望得到一个bytes实例,需要在文本之前添加b字符。

全文 http://www.jianshu.com/p/4f0e65bee38b
作者:wwlovett 链接:http://www.jianshu.com/p/4f0e65bee38b 來源:简书 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
 
1 >>> s='hello,world'
2 >>> s
3 'hello,world'
4 >>> type(s)
5 <class 'str'>
6 >>> h=b'hello,world'
7 >>> type(h)
8 <class 'bytes'>

3.#文本总是unicode字符集,用str类型表示。二进制数据则由bytes表示。(通过socket在网络上传输数据时必须要用二进制格式)

Python不会以任何隐式的方式混用str和bytes,所以我们不能在代码中拼接字符串和字节包

当然字符串和字节,是可以被相互转换的。借用一个图来说明转换关系:

 

 

str通过encode 编码成 bytes 类型,而bytes格式的数据又可以通过decode来解码成str类型。
 
encode 用来对string格式个数据进行编码:
#encode 用来对str(文本字符串)格式的数据进行编码:
1
>>> s='你好' 2 >>> s.encode() #不指定目的格式,则默认'utf-8' 3 b'\xe4\xbd\xa0\xe5\xa5\xbd' 4 >>> s.encode('utf-8') #验证下,果然默认和设定为'utf-8'是一致的输出格式 5 b'\xe4\xbd\xa0\xe5\xa5\xbd'

decode 用来对bytes格式的数据进行解码:

1 >>> s=b'\xe4\xbd\xa0\xe5\xa5\xbd'
2 >>> s.decode('utf-8')    #表示把二进制字节字符串解释成 什么格式的数据(默认UTF-8)
3 '你好'

数据处于 网络传输 磁盘存储状态下,必须以'二进制字节字符串'(即'字节流')形式存在,即b'\x_ _\x_ _\x_ _\x_ _

A.在计算机内存中,统一使用Unicode编码(str),当需要保存到硬盘或者                                      B.  浏览网页的时候,服务器会把动态生成的Unicode内容(str)转

需要传输(bytes)的时候,就转换为UTF-8编码。                                                                                  换为UTF-8(bytes)再传输到浏览器:    

                                                                                                                                                    


4#读取文件 python3:

文件总是存储字节,因此,为了使用文件中读取的文本数据,必须首先将其解码为一个文本字符串。 python3中,文本正常情况下会自动为你解码,所以打开或读取文件会得到一个文本字符串。 使用的解码方式取决系统,在mac os 或者 大多数linux系统中,首选编码是utf-8,但windows不一定。 可以使用locale.getpreferredencoding()方法得到系统的默认解码方式。


1 #Python3 把系统默认编码设置为 UTF-8
2 >>> import sys
3 >>> sys.getdefaultencoding()
4 'utf-8'

自己找个例子验证下是否已经掌握

 1 >>> '深蓝'
 2 '深蓝'
 3 >>> type('深蓝')   
 4 <class 'str'>     #随意输入的数据在python内部已经被默认为 ‘文本字符串’=str,此时的str为 unicode类无编码数据
 5 
 6 >>> '深蓝'.decode('utf-8')  #傻傻的试下,果然str是无法被解码的(人家已经是unicode了,还解什么?解码的目的就是变成unicode嘛),程序报错了<str无法使用decode函数功能>
 7 Traceback (most recent call last):
 8   File "<stdin>", line 1, in <module>
 9 AttributeError: 'str' object has no attribute 'decode'
10 
11 >>> '深蓝'.encode('utf-8')  #看看能编码否
12 b'\xe6\xb7\xb1\xe8\x93\x9d'  #OK,str被顺利用utf-8规则编码为 字节字符串了(此时的数据可以被网络传输或存入硬盘了,它已处于从python出口待output状态了)
13 >>> type('深蓝'.encode('utf-8'))
14 <class 'bytes'>  #不放心验证下,数据确是bytes了
15 
16 >>> print('深蓝'.encode('utf-8').decode('utf-8')) #想要再次的得到数据的'文本字符串'形式,必须再次解码(decode)
17 深蓝

 python如何判断对象是否为字符串或者其他类型?

 

 1 >>> a=10
 2 >>> b='中华'
 3 >>> print(isinstance(a,int))               
 4 True
 5 >>> print(isinstance(b,str))
 6 True
 7 >>> print(isinstance(a,str))
 8 False
 9 >>> print(isinstance(b,float))
10 False
>>> print(isinstance('中华',str))
True

 避免乱码,坚持几点:

1、坚持使用UTF-8编码对str和bytes进行转换。

2、源代码中包含中文的时候,在保存源代码时,就需要务必指定保存为UTF-8编码。

3、当Python解释器读取源代码时,为了让它按UTF-8编码读取,我们通常在文件开头写上这两行:

1 #!/usr/bin/env python3       < 告诉Linux/OS X系统,这是一个Python可执行程序,Windows系统会忽略 >
2 # -*- coding: utf-8 -*-    < 告诉Python解释器,按照UTF-8编码读取源代码 >

4、确保文本编辑器正在使用<UTF-8 without BOM>编码


  由于一直在看廖雪峰老师的教程学习py,但他讲的稍显简略,属于提纲挈领的体会型教程。而我个人学东西特喜欢刨根问底,而且喜欢发散思维,喜欢以点带面,但缺点也很明显——对于暂时搞不懂的难点,很难跨过去继续学习后面内容,导致遇到问题就卡壳。
例如遇到了py编码问题,我就想深入的把编码类问题一次性全部弄通,虽然有朋友告诫我,初学应该抓大放小 、注重体验,有些难点可以后补或者学完再思考,这次编码问题我困惑了足足2天,起码10个小时。后来我知道了是由于py2.0-3.0阶段的版本大更新问题导致语法结构的巨变,使得我浪费了太多时间。以后不会了,决定采用朋友的告诫,先弄通一个流程,建立起基本框架再补全各类问题。

PS:编码问题太痛苦了,好了好了,赶紧翻篇~~

 

posted @ 2017-09-29 03:59  深藍  阅读(633)  评论(0编辑  收藏  举报