-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
f4158dc
commit b5ae2cf
Showing
2 changed files
with
93 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
## 楔子 | ||
|
||
接下来我们将分析 Python 的字符串,这应该是使用频率最高的数据结构了,我们会通过多篇文章来详细阐述字符串的实现原理。 | ||
|
||
首先字符串是一个变长对象,因为不同长度的字符串所占的内存是不一样的。但同时字符串又是一个不可变对象,因为一旦创建就不可以再修改了。 | ||
|
||
## 多字节编码 | ||
|
||
我们知道计算机的存储单位是字节,一个字节可以表示 256 种字符,对于发明计算机的美国人来说足够了。因为英文字母算上大小写只有 52 个,即便再加上一些特殊字符,数量也不会超过 256 个,因此一个字节完全可以表示。 | ||
|
||
但随着计算机的普及,越来越多的非英文字符出现,导致一个字节已经无法表示了。所以只能曲线救国,对于一个字节无法表示的字符,使用多个字节表示,这便是<font color="blue">多字节编码</font>。而多字节编码也存在相应的问题,就是容易出现乱码。 | ||
|
||
到这里先不继续往下深入,我们先来理清楚一些概念。 | ||
|
||
## 字符集和字符编码 | ||
|
||
估计有很多小伙伴搞不清这两者的区别,我们先来解释一下所谓的字符集和字符编码是怎么一回事? | ||
|
||
+ <font color="blue">字符集</font>:系统支持的所有字符组成的集合,像 ASCII、GB2312、Big5、unicode 都属于字符集。只不过不同的字符集所能容纳的字符个数不同,比如 ASCII 字符集不包含中文,unicode 则可以容纳世界上的所有字符; | ||
+ <font color="blue">多字节编码</font>:负责将每个字符转成一个或多个计算机可以接受的具体数字,该数字可以理解为编号,因此字符编码维护了字符和编号之间的对应关系。而编码也分为多种,比如 ASCII、GBK、UTF-8 等等,字符编码不同,那么字符转换之后的编号也不同,当然能转化的字符种类也不同。比如 ASCII 这种字符编码,它就只能转换 ASCII 字符。 | ||
|
||
当然,ASCII 比较特殊,它既是字符集、也是字符编码。并且不管采用什么编码,ASCII 字符对应的编号永远是相同的。 | ||
|
||
将字符串中的每一个字符转成对应的编号,那么得到的就是<font color="blue">字节序列(bytes 对象)</font>,因为计算机存储和网络通讯的基本单位都是字节,所以字符串必须以字节序列的形式进行存储或传输。 | ||
|
||
因此字符串和字节序列在某种程度上是很相似的,字符串按照指定的编码进行 encode 即可得到字节序列,<font color="blue">也就是将每个字符都转成对应的编号</font>;字节序列按照相同的编码 decode 即可得到字符串,<font color="blue">也就是根据编号找到对应的字符</font>。 | ||
|
||
比如我们写了一段文本,然后在存储的时候必须先进行 encode,也就是将每一个字符都转成一个或多个系统可以接受的数字、即对应的编号之后,才可以进行存储。 | ||
|
||
~~~Python | ||
name = "古明地觉" | ||
|
||
print(name.encode("gbk")) | ||
""" | ||
b'\xb9\xc5\xc3\xf7\xb5\xd8\xbe\xf5' | ||
""" | ||
print(name.encode("utf-8")) | ||
""" | ||
b'\xe5\x8f\xa4\xe6\x98\x8e\xe5\x9c\xb0\xe8\xa7\x89' | ||
""" | ||
~~~ | ||
|
||
采用不同的编码,得到的字节序列是不同的,比如使用 gbk 编码 encode,那么也必须使用 gbk 编码 decode。否则会因为无法解析而报错,因为字符编码不同,字符对应的编号也不同。 | ||
|
||
再比如每个国家都有自己的字符编码,你在日本的一台计算机上写好的文件拿到中国的计算机上打开,很有可能出现乱码。因为字符编码不同,字符和编号之间的对应关系也不同,采用不同的字符编码进行解析肯定会出问题。 | ||
|
||
但我们说,对于 ASCII 字符来说,由于不管采用哪一种编码,它们得到的编号都是固定的。所以编码对于 ASCII 字符来说,没有任何影响。 | ||
|
||
~~~Python | ||
name = "satori" | ||
|
||
print(name.encode("gbk")) | ||
""" | ||
b'satori' | ||
""" | ||
print(name.encode("gbk").decode("utf-8")) | ||
""" | ||
satori | ||
""" | ||
|
||
# 但如果是非 ASCII 字符,就不行了 | ||
try: | ||
"你好".encode("gbk").decode("utf-8") | ||
except UnicodeDecodeError as e: | ||
print(e) | ||
""" | ||
'utf-8' codec can't decode byte 0xc4 in position 0: invalid continuation byte | ||
""" | ||
~~~ | ||
|
||
这里再回忆一下 bytes 对象,创建的时候可以采用字面量的方式,比如 <font color="blue">b"abc"</font>,但是 <font color="blue">b"憨"</font> 却不可以。原因就是<font color="blue">憨</font>这个字符不是 ASCII 字符,那么采用不同的字符编码,其对应的编号是不同的。而解释器又不知道我们使用的是哪一种编码,所以不允许这么做,而是需要通过 <font color="blue">"憨".encode()</font> 的方式手动指定字符编码。 | ||
|
||
但对于 ASCII 字符而言,不管采用哪一种字符编码,得到的编号都是一样的, 所以 Python 针对 ASCII 字符则允许这种做法,比如 <font color="blue">b"abc"</font>。并且我们看到,对于汉字来说,在编码之后会对应多个编号,而每个编号占 1 字节,因此不同的字符所占的大小可能不同。 | ||
|
||
## 小结 | ||
|
||
以上就是字符集和字符编码,字符集就是字符组成的集合,不同字符集所能容纳的字符数量是有限的。字符编码是将字符转成对应的编号,比如将一个字符串中的所有字符都转成对应的编号之后,就得到了字节序列。当然和字符集一样,字符编码能转换的字符种类也是有限的,像汉字我们可以使用 GBK 编码、UTF-8 编码,但是不能使用 ASCII 编码。 | ||
|
||
以上算是理清楚了一些概念,显然过于简单了,主要是为后面的内容做铺垫。那么下一篇文章,我们就从 Python 的角度来分析字符串的存储方式。 | ||
|
||
---------------- | ||
|
||
| ||
|
||
**欢迎大家关注我的公众号:古明地觉的编程教室。** | ||
|
||
![](./images/qrcode_for_gh.jpg) | ||
|
||
**如果觉得文章对你有所帮助,也可以请作者吃个馒头,Thanks♪(・ω・)ノ。** | ||
|
||
![](./images/supports.png) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters