记录学习《流畅的python》的一些知识-----字符(1)

记录我学习《流畅的python》的过程

2021.1.9

1.字符问题

s = 'café'

print(len(s))

b = s.encode('utf8')
print(b)
print(len(b))
print(b.decode('utf8'))


cafe = bytes('café', encoding='utf_8')
print(cafe)

print(cafe[0])
print(cafe[:1])

cafe_arr = bytearray(cafe)
print(cafe_arr)

print(cafe_arr[-1:])

运行结果:
在这里插入图片描述

使用数组中的原始数据初始化bytes对象:

import array
numbers = array.array('h', [-2, -1, 0, 1, 2])
octets = bytes(numbers)
print(octets)

问:为什么把一些数据转换成字节的形式?
这是计算机原理基础的问题,下面是一些博主给出的一些答案。
在这里插入图片描述
学习计算机原理时应该学习到硬件的历史和过去的原理。

较早较流行(制订了今天的标准)的计算机,是8为计算机(更少位数的被淘汰了!)。指令、数据总线的宽度都是8位,因此发送一次信息都要并行改变8个bit的状态。你要是不按8bit去设计软件控制逻辑,反而是浪费了n倍的时间。

尽管后来标准升级为16bit,但是仍然为了软件兼容而特意降低了计算机效率(浪费了许多空间把8bit的数据放到16bit的空间内)、保留了byte的格式。

如果当初订立的标准是64bit数据总线宽度宽度,那么你今天看到的byte就是64bit了,而不是8bit了。

所以不管你觉得什么更省空间,实际情况的发展都是更强的。人不可能按照自己的想象来要求别人,不能那样去要求计算机体系设计。
在这里插入图片描述
假设可以传输bit,那么你传输/保存一组bit,因为你的目的是按最小的空间来保存数据,那么假设你传输了一个数字3,传输了一个bit[]=>11,那么读取出你这11之后,我怎么知道我应该读2bit还是读1个bit还是读10个bit?你是不是需要再多传一个数字,表明之前传的数字实际占用了几个bit?那么你新传的这个数字又怎么确定到底是几个bit的?是不是又要再传一个数字?如此循环往复……还是定个规则?规定8个bit一组活着16/32/64个bit一组,每组默认代表一个数字/字符。那就是现在用byte的做法。

你这是用高级语言的思想思考底层问题又对底层实现本身不了解。你的想法那是最简单的压缩算法的基础,最简单的比如利用哈夫曼树编码来实现数据压缩,用尽量小的bit来存储数据,代价就是需要一个字典表,字典表又分动态/静态。动态的需要随压缩数据传输/保存,静态的需要预先定义,但没法做到完全不浪费bit位。具体你可以自己实现一个哈夫曼编码来体会一下。

2.结构体和内存视图
struct模块提供了一些函数,把打包的字节转换成不同类型字段组成的元组,还有一些函数用于执行反向转换,把元组转换成打包的字节序列。
如memoryview类不是用于创建或存储字节序列的,而是共享内存,让你访问其他二进制序列,打包的数组和缓冲中的数据切片,而无需复制字节序列。
使用mmap模块把图像打开为内存映射文件,那么会复制少量字节。

import struct
fmt = '<3s3sHH'  #结构体的格式:<是小字节序,3s3s是两个3字节序列,HH是两个16位二进制整数
with open('filter.gif.jpg', 'rb') as fp:
    img = memoryview(fp.read())

header = img[:10]
print(bytes(header))
print(struct.unpack(fmt, header))

运行结果:
在这里插入图片描述
运行下面的代码即删除引用,释放memoryview实例所占的内存。

del header
del img

3.基本的编解码器
使用三个编解码器编码字符串:

for codec in ['latin_1', 'utf_8', 'utf_16']:
    print(codec, 'EL Niéo'.encode(codec), sep='\t')

运行结果:
在这里插入图片描述
编解码器:
1.ASCII ASCII ((American Standard Code for Information Interchange): 美国信息交换标准代码)是基于拉丁字母的一套电脑编码系统,主要用于显示现代英语和其他西欧语言(百度)
2.latin1 一种重要的编码,是其他编码的基础。
3.cp1252 Microsoft制定的latin1超集,添加了有用的符号。
4.cp437 IBM PC最初的字符集,包含框图符号
5.gb2312 用于编码简体中文的陈旧标准。
6.utf-8 目前Web中最常见的8位编码,与ASCII兼容(纯ASCII文本是有用的UTF-8序列)
7.utf-16le UTF-16的16位编码方案的一种形式。

4.编码问题
UnicodeEncodeError:字符串转换成二进制序列时
UnicodeDecodeError:二进制转换成字符串时
SyntaxError

city = 'Sāo Paulo'
print(city.encode('utf_8'))
print(city.encode('utf_16'))
print(city.encode('iso8859_1'))

运行结果:
在这里插入图片描述

iso8859_1编码不能处理字符串

city = 'Sāo Paulo'
print(city.encode('utf_8'))
print(city.encode('utf_16'))
print(city.encode('iso8859_1', errors='ignore')) #跳过无法编码的字符
print(city.encode('iso8859_1', errors='replace')) #把无法编码的字符替换成?
print(city.encode('iso8859_1', errors='xmlcharrefreplace')) #把无法编码的字符替换成XML实体

运行结果:
在这里插入图片描述
解码:

octets = b'Montr\xe9al'#使用的是latin1编码的,\xe9字节对应é
print(octets.decode('cp1252'))
print(octets.decode('iso8859_7'))#iso用于编码希腊文,无法正常解码
print(octets.decode('koi8_r'))#koi8编码俄文
print(octets.decode('utf_8', errors='replace'))#不是有效utf_8字符串

运行结果:
在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值