python - bytes & 编码解码

目录

bytes

str 转 bytes

bytes 转 str

编码解码

base64

URL

参考


经常遇到 bytes 对象的使用会懵逼,故写点笔记。

bytes

str 转 bytes

相对于字符串以字符为单元进行操作,bytes 则以字节为单元进行操作,可以理解为“字节串”(注意,这不是专业术语,只是便于理解的叫法)。看一段代码:

mybytes = b"hello world"           // (1)
mybytes2 = b"好好学习"              // (2)error
mybytes3 = bytes("好好学习", encoding="utf8")     // (3)
mybytes4 = bytes("hello 世界", encoding="utf-8")  // (4)
mybytes5 = "hello 世界".encode("utf-8")  // (5)

(1)字符串前加个 "b" 就是将 "hello world" 字符串转换为 bytes 对象。但最迷惑的是,这段字符串以什么样的字节存储。答案是:如果字符串是一串 ASCII 字符,那么就存储它们的 ASCII 值。所以这里 mybytes 存储的是:

h          e        l         l         o       <空格>     w        o        r       l         d 
01101000 01100101 01101100 01101100 01101111 00100000 01110111 01101111 01110010 01101100 01100100

(2)如果字符串是一串非 ASCII 码,那么不能使用前缀 b 将字符串转换成 bytes 对象:

错误信息标明只能包含 ASCII 码范围内的字符。

(3)所以,必须用构造函数将字符串转换成 bytes 对象,并且要指定第二个参数,也就是字符集。可以这样理解,我们现在所看到的字符串,例如"好好学习",只是 4 个字符图像,实际在内存中存储什么样的字节内容,就得看给程序指定了哪种字符集,比如指定 utf8:

UTF-8 用 3 个字节存储汉字,所以字节串长度就有 4*3=12 个。默认情况下,python 使用的字符集是 UTF-8。

(4)如果字符串既有 ASCII 字符,又有汉字,那么仍然需要指定字符集。

UTF-8 对 ASCII 字符用一个字节存储,用三个字节存储汉字,所以这里 6+3*2=12 个字节。注意,在控制台输出 bytes 对象时,对 ASCII 字符仍然是打印它们的字符图像,而其他非 ASCII 字符就打印它们的十六进制。

bytes 转 str

用 bytes 对象的 decode() 方法将字节串重新转换成字符串。默认使用 UTF-8 解码,所以一般将字符串转换为 bytes 对象时指定 UTF-8 字符集:

>>> b = bytes("hello 世界",encoding="utf-8")
>>> b
b'hello \xe4\xb8\x96\xe7\x95\x8c'
>>> b.decode()
'hello 世界'
>>> b.decode(encoding="utf-8")
'hello 世界'

当然,也可以用其他字符集,例如 GBK,不过 decode() 就必须指定同样的字符集,否则可能会报错:

>>> b = bytes("hello 世界", encoding="gbk")
>>> b
b'hello \xca\xc0\xbd\xe7'
>>> b.decode()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xca in position 6: invalid continuation byte
>>> b.decode(encoding="gbk")
'hello 世界'

hex 转 bytes

现在有一个十六进制字符串:

str = "342ec70264b61f9749aa17558239eddb"

这只是一个以字符串的形式表示一串 0 与 1,注意只是形式,str 变量实际存储的是每个字符的 ASCII 码:

   3        4         2       e      ...
00110011 00110100 00110010 01100101 01....

但我们希望存储的是十六进制转换成的二进制,也就是这样的:

  3    4   2    e    ..
0011 0100 0010 1110 11...

那么这就不能用字符串类型存储了,而是用 bytes 对象。用 bytes.fromhex() 可以将十六进制字符串转换成对应的二进制字节串

>>> bytes.fromhex("342ec70264b61f9749aa17558239eddb")
b'4.\xc7\x02d\xb6\x1f\x97I\xaa\x17U\x829\xed\xdb'

bytes 转 hex

bytes.hex() 将二进制字节串用十六进制字符串表示

>>> bytes.fromhex("342ec70264b61f9749aa17558239eddb")
b'4.\xc7\x02d\xb6\x1f\x97I\xaa\x17U\x829\xed\xdb'
>>> bytes.fromhex("342ec70264b61f9749aa17558239eddb").hex()
'342ec70264b61f9749aa17558239eddb'

编码解码

base64

使用 base64 模块,方法:

  • base64.b64encode(bytes)
  • base64.b64decode(str)

例子:

>>> import base64
>>> base64.b64encode(b"hello world")
b'aGVsbG8gd29ybGQ='
>>> base64.b64decode("aGVsbG8gd29ybGQ=")
b'hello world'

如果有非 ASCII 字符,就用 bytes 构造函数:

>>> b = bytes("hello 世界", encoding="utf-8")
>>> base64.b64encode(b)
b'aGVsbG8g5LiW55WM'
>>> base64.b64decode("aGVsbG8g5LiW55WM")
b'hello \xe4\xb8\x96\xe7\x95\x8c'
>>> base64.b64decode("aGVsbG8g5LiW55WM").decode()
'hello 世界'

base64 解码后得到的是 bytes 对象,可以调用 decode() 方法将其转换为字符串。

URL

用到 urllib.quote 模块,方法:

  • quote(str)
  • unquote(str)

例子:

>>> from urllib.parse import quote,unquote,urlencode
>>> quote("好好学习")
'%E5%A5%BD%E5%A5%BD%E5%AD%A6%E4%B9%A0'
>>> unquote("%E5%A5%BD%E5%A5%BD%E5%AD%A6%E4%B9%A0")
'好好学习'

 默认使用 UTF-8 字符集。不过 quote() 并非完全编码,只是对非 URL 规定的字符编码,例如:

>>> quote("+,ab'")
'%2B%2Cab%27

其中 a 和 b 就没有被 URL。所以,如果进行完全 URL 编码,可以遍历每个字符,得到它们的十六进制数字,然后在前面拼接 "%"。

参考

http://c.biancheng.net/view/2175.html

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值