流畅的python:文本和字节序列-Part1

文本和字节序列(上)

人类使用文本,计算机使用字节序列。

本章将要讨论Unicode字符串、二进制序列,以及在二者之间转换时使用的编码。深入理解Unicode对你可能十分重要,也可能无关紧要,这取决于Python编程的场景。说到底,本章涵盖的问题对只处理ASCII文本的程序员没有影响。但是或许你跟我一样执着于输入输出的完美,或者有更多使用字符串的复杂场景,或许你应该看一看这一章。

1、基础知识

计算机中储存的信息都是用二进制数表示的;而我们在屏幕上看到的英文、汉字等字符是二进制数转换之后的结果。通俗的说,按照何种规则将字符存储在计算机中,如’a’用什么表示,称为"编码"encode;反之,将存储在计算机中的二进制数解析显示出来,称为"解码"decode。在解码过程中,如果使用了错误的解码规则,就会导致解码错误或者乱码。

字符集(Charset):是一个系统支持的所有抽象字符的集合。字符是各种文字和符号的总称,包括各国家文字、标点符号、图形符号、数字等。常见字符集名称:ASCII字符集、GB2312字符集、BIG5字符集、GB18030字符集、Unicode字符集等。

字符编码(Character Encoding):是一套配对法则,比如ASCII中的’0’对应于49,两者是对应的关系:

>>>chr(48)
'0'
>>>ord('0')
48

1.1 ASCII

这个大家都很熟悉,是现今最通用的单字节编码系统。使用7位(bits)表示一个字符,共128字符,为了表示更多的欧洲常用字符对ASCII进行了扩展,ASCII扩展字符集使用8位(bits)表示一个字符,共256字符。最大缺点是只能显示26个基本拉丁字母、阿拉伯数目字和英式标点符号,因此只能用于显示现代美国英语。

1.2 GB2312

这是我天朝的编码系统啊,主要目的就是显示中文,中国大陆几乎所有的中文系统和国际化的软件都支持GB2312,比如MATLAB。

GB2312保留了ASCII小于127的字符的意义,但两个大于127的字符连在一起时,就表示一个汉字,前面的一个字节(称为高字节)从0xA1用到 0xF7,后面一个字节(低字节)从0xA1到0xFE,这样我们就可以组合出大约7000多个简体汉字了。在这些编码里,还把数学符号、罗马希腊的 字母、日文的假名们都编进去了,连在ASCII里本来就有的数字、标点、字母都统统重新编了两个字节长的编码,这就是常说的"全角"字符,而原来在127号以下的那些就叫"半角"字符了。

1.3 Unicode

Unicode统一码万国码单一码标准万国码)是业界的一种标准,**从Python 3的str对象中获取的元素就是Unicode字符。**它可以使电脑得以体现世界上数十种文字的系统,并且还在不断扩增。对应的编码规则有UTF-32/ UTF-16/ UTF-8

  1. UTF-32

    使用4字节的数字来表达每个字母、符号,或者表意文字,最大的优点就是可以在常数时间内定位字符串里的第N个字符,因为第N个字符从第4×Nth个字节开始,但是非常浪费空间,所以用处并不广泛。

  2. UTF-16

    尽管Unicode字符非常多,但是实际上很少用到超过前65535个以外的字符。因此,就有了另外一种Unicode编码方式,叫做UTF-16(16位 = 2字节),对于65535以内的,只用两个字节表示,但是之外的就需要诡异的技巧,在这里我们就不说了。

  3. UTF-8

    UTF-8是一种针对Unicode的可变长度字符编码,可以用来表示Unicode标准中的任何字符,且其编码中的第一个字节仍与ASCII兼容,这使得原来处理ASCII字符的软件无须或只须做少部份修改,即可继续使用。因此用途非常广泛。

    UTF-8使用一至四个字节为每个字符编码:

    • 128个US-ASCII字符只需一个字节编码(Unicode范围由U+0000至U+007F)。
    • 带有附加符号的拉丁文、希腊文、西里尔字母、亚美尼亚语、希伯来文、阿拉伯文、叙利亚文及它拿字母则需要二个字节编码(Unicode范围由U+0080至U+07FF)。
    • 其他基本多文种的字符使用三个字节编码(比如中文)。
    • 其他极少使用的字符使用四字节编码。

    不过因为每个字符使用不同数量的字节编码,所以寻找串中第N个字符是一个O(N)复杂度的操作。同时,还需要位变换来把字符编码成字节,把字节解码成字符。

2、编码与解码

非常简单:

str -> bytes: encode编码
bytes -> str: decode解码

>>> s = '中文'
>>> len(s)
2
>>> b= s.encode('utf8') # 把str转换为bytes
>>> b # 1.
b'\xe4\xb8\xad\xe6\x96\x87'
>>> len(b) # 2.
6
>>> b.decode('utf16') # 3.
'룤\ue6ad螖'
>>> b.decode('utf8')
'中文'
  1. 将字符串转换为字节序列,前面的b前缀表示是字节
  2. 知道为啥是6吧,utf-8中汉字占用3个字节
  3. 错误的解码规则就会导致乱码、

除此之外,还可以使用bytes和str函数进行编解码:

# str 转 bytes:
bytes('中国', encoding='utf-8')

# bytes 转 str:
str(b'\xe4\xb8\xad', encoding='utf-8')

3、字节概要

Python内置了两种基本的二进制序列类型:Python 3引入的不可变bytes类型和Python 2.6添加的可变bytearray类型。bytes或bytearray对象的各个元素是介于0~255(含)之间的整数。

>>> cafe = bytes('café', 'utf8')
>>> cafe
b'caf\xc3\xa9'
>>> cafe[0]
99
>>> cafe[4]
169
>>> cafe[:1]
b'c'
>>> cafe_arr=bytearray(cafe)
>>> cafe_arr
bytearray(b'caf\xc3\xa9')
>>> cafe_arr[-1]
169
>>> cafe_arr[-1:]
bytearray(b'\xa9')

虽然二进制序列其实是整数序列,但是它们的字面量表示法表明其中有ASCII文本。因此,各个字节的值可能会使用下列三种不同的方式显示:

  • 可打印的ASCII范围内的字节(从空格到~),使用ASCII字符本身。
  • 制表符、换行符、回车符和\对应的字节,使用转义序列\t、\n、\r和\。
  • 其他字节的值,使用十六进制转义序列(例如,\x00是空字节)。

就像b’caf\xc3\xa9’,前三个就是ASCII字符。cafe是一个bytes对象,长度是5,caf都是ASCII码,在utf8编码方式中只需要占一个字节,带符号的é占两个字节。cafe[0]和cafe[:1]不一致我想你不会大惊小怪吧,cafe[0]获取的是一个元素,99对应于’c’;cafe[:1]是切片,返回的是与原始序列相同数据类型的序列,即使这个序列只有1个元素。

——未完待续——
欢迎关注我的微信公众号
扫码关注公众号

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值