流畅的python,Fluent Python 第四章笔记

4.1字符问题:

字符的标识即码位,是一串数字,再unicdoe中以4-6个16进制数标识。(其实码位就时字符了,就好比我的名字是小明,小明就是我。再py3,unicode直接输出文字,在py2里print输出unicode也时具体文字)

字符的具体表述取决于所用的编码。编码是在码位和字节序列之间转换时使用的算法。

把码位转换成字节序列的过程叫做编码;把字节序列转换成码位的过程叫做解码。

简单理解,编码时给机器用的,解码后是给人用的。

4.2字节该要

In [687]: b'\xc3\xa9'.decode('U8')                                                                                      
Out[687]: 'é'

In [688]: cafe = bytes('café', encoding='utf8')                                                                         

In [689]: cafe                                                                                                          
Out[689]: b'caf\xc3\xa9'

In [690]: cafe[0]                                                                                                       
Out[690]: 99

In [691]: cafe[-1]                                                                                                      
Out[691]: 169

In [692]: cafe[-1:]                                                                                                     
Out[692]: b'\xa9'

In [693]: cafe = bytearray(cafe)                                                                                        

In [694]: cafe                                                                                                          
Out[694]: bytearray(b'caf\xc3\xa9')

In [695]: cafe[0]                                                                                                       
Out[695]: 99

In [696]: cafe[-1]                                                                                                      
Out[696]: 169

In [697]: cafe[-1:]                                                                                                     
Out[697]: bytearray(b'\xa9')

In [698]: '12345'[2:3] == '12345'[2]                                                                                    
Out[698]: True

 通过代码可以看到,bytesyubytesarray的各个元素都是介于0-255(含)【两个16进制数字的区间,二进制111111111,8个1最大就是255】之间的整数。

二进制序列的切片始终是同以类型的二进制序列,包括长度位1的切片。

可迭代对象的切片中,从上面可以看出,只有str可以做到,取值于切片是一样的。

另外的取值是取值,切片出来的一个相同类型的序列,里面包含这个取值的元素。

好比s[i] 是取出迭代中的i值,s[i :i+1]取出的是s[i]

从输出可以看到,字节序列只有三种不同的方式显示

1、可以打印的ASCII范围内的字节,使用ASCII字符自身

2、制表符、换行符、回车符和\,就是\t \n \r \\

3、就是\x啦啦,啦啦为两个16进制数字

字节序列可以用很多字符串的方法,除了那些判断字符串属性的以外,可以简单的认为也是一个字符串,只不过是一个比较特殊的二进制字符串。

In [753]: bytes.fromhex('314bcea9')                                                                                     
Out[753]: b'1K\xce\xa9'

 这是bytes特有的方法,可以从字符串直接转换为字节序列,31于4b因为刚好对应ASCII的1于K所以直接输出了1于K,当时卡住我老半天。

如何创建一个字节序列对象呢。

1、最直接

In [752]: '!love你,\n'.encode()                                                                                         
Out[752]: b'!love\xe4\xbd\xa0,\n'

 上面可以看出来,标点符号,英文字母都输出来了,就是中文被输出了另外的。

构建bytes或bytearray实例还可以调用各自的构造方法,传入下述参数。

1、一个str对象和一个encoding关键字参数

2、一个可迭代对象,提供0-255之间的数值(难道就我前面写的fromhex)

3、一个实现了缓冲协议的对象(如bytes、bytearray、memoryview、array.array);此时把源对象中的字节序列复制到新建的二进制序列中。

(啥叫缓冲协议对象,我查不到资料,郁闷。)书中代码上一下

In [754]: numbers = array.array('h',[-2,-1,0,1,2])                                                                      

In [755]: octets = bytes(numbers)                                                                                       

In [756]: octets                                                                                                        
Out[756]: b'\xfe\xff\xff\xff\x00\x00\x01\x00\x02\x00'

In [757]:  

 不知道这样又有什么意思?而且我试过bytes后面就算不同的0-255之内的数字也可以输出。

In [761]: bytes([1,2,3,4,5,233])                                                                                        
Out[761]: b'\x01\x02\x03\x04\x05\xe9'

In [762]:  

 后面讲了结构体于内存视图

struct于meneryview,struct是用来操作二进制数据的,没咋看懂,就不上代码,也不写了。

4.3基本的编解码器

Python自带100多种解码器,很多。

常用的utf-8可以写成utf8,U8

unicode的字符除了utf-8 utf-16可以全部找到对应的字节次序,另外的都不全,再decode编码的时候,如果碰到自己字符集没有的字符,默认设置就会报错。

4.4了解编码问题

如果你不用utf-8去decode遇到自己没有的字符集就会报错。

In [762]: s = 'abs我cd'                                                                                                 

In [763]: s.encode(encoding='adcii')                                                                                    
---------------------------------------------------------------------------
LookupError                               Traceback (most recent call last)
<ipython-input-763-c481354da0b9> in <module>
----> 1 s.encode(encoding='adcii')

LookupError: unknown encoding: adcii

In [764]: s.encode(encoding='ascii')                                                                                    
---------------------------------------------------------------------------
UnicodeEncodeError                        Traceback (most recent call last)
<ipython-input-764-8fa11c3441f2> in <module>
----> 1 s.encode(encoding='ascii')

UnicodeEncodeError: 'ascii' codec can't encode character '\u6211' in position 3: ordinal not in range(128)

In [765]: s.encode(encoding='ascii',errors='ignore')                                                                    
Out[765]: b'abscd'

In [766]: s.encode(encoding='ascii',errors='replace')                                                                   
Out[766]: b'abs?cd'

In [767]: s.encode(encoding='ascii',errors='xmlcharrefreplace')                                                         
Out[767]: b'abs&#25105;cd'

In [768]:         

 有三个参数可以选择,最后一个参数有意思,网页上面尽然又显示出来这个我字了

In [767]: s.encode(encoding='ascii',errors='xmlcharrefreplace')                                                         
Out[767]: b'abs我cd'

 书中还说,error的参数是可扩张的。

当然decode也一样了

In [770]: s                                                                                                             
Out[770]: 'abs我cd'

In [771]: s.encode('U8').decode('ascii',errors='ignore')                                                                
Out[771]: 'abscd'

In [772]: s.encode('U8').decode('ascii',errors='replace)                                                                
  File "<ipython-input-772-ed017d19dba1>", line 1
    s.encode('U8').decode('ascii',errors='replace)
                                                  ^
SyntaxError: EOL while scanning string literal


In [773]:      

 用用utf-8时建议写replace,因为会给一个默认的替代字符,这笔调过这个字好多了

4.4.4如何找出字节序列的编码

用chardet.detect

In [774]: string = '我是大叔阿瓜'                                                                                       

In [775]: import chardet                                                                                                

In [776]: gg = string.encode('gbk')                                                                                     

In [777]: uu = string.encode()                                                                                          

In [778]: chardet.detect(gg)                                                                                            
Out[778]: {'encoding': None, 'confidence': 0.0, 'language': None}

In [779]: chardet.detect(uu)                                                                                            
Out[779]: {'encoding': 'utf-8', 'confidence': 0.99, 'language': ''}

In [780]: chardet.detect('师傅登革热特哥时代风范厄尔人'.encode('gbk'))                                                  
Out[780]: {'encoding': 'GB2312', 'confidence': 0.99, 'language': 'Chinese'}

In [781]:  

 字符数据越多越准确。

4.5处理文本文件。

在用open处理文本文件的时候,encoding不要使用系统默认的,容易出问题。

然后就是尽量使用linux系统电脑,因为系统里面所有的编码,解码都是基于utf-8的,

这样可以字节序列于字符编码,解码时候的错误。

我们处理文档默认的编码为:

In [810]: locale.getpreferredencoding()                                                                                 
Out[810]: 'UTF-8'

4.6为了正确比较而规范化Unicode字符串(感觉用到的机会不大)

后面基本都是基于国外文字,德文,拉丁文相关的unicdoe处理,我稍微看了下。就不写了。

猜你喜欢

转载自www.cnblogs.com/sidianok/p/12057756.html