深入理解Python字符编码

转载请附本文链接https://blog.csdn.net/maxlovezyy/article/details/106166480

基础知识

在计算机诞生之初只需要英文字母和数据以及一些基本的标点符号就够用了,最初的版本就是用[0,128)这128个数字来表示不同的符号,所以就有了ASCII这样一套编码规范。但是后来随着计算机的普及,ASCII能表示的字符就不够了,很明显的是不支持非英文字母的语言文字,比如汉字等。所以之后就有了一个统一的、涵盖范围更广泛的字符编码规范,称之为Unicode(Q1),其中包含了多国语言,是一个国标准,目前最广泛使用的跨平台兼容的一个标准。

现在编码标准有了,也就是有了数字(称之为码点,code point)到具体字符的映射,而计算机只认识01,需要把码点表示的字符编码为计算机能够识别的bytes,这就是编码。比如一个最naive的思路就是可以用第一个byte的第1位作为第一个byte的标志位,后续的bytes的解释通过第一个byte的值识别解释方式。对于编码有着各种各样的标准,从最初的ASCII到UTF-16、UTF-32、UTF-8,目前最流行的就是UTF-8。UTF-8是兼容ASCII的,UTF-8也是内存比较序与Unicode码点一致的(可以参考维基百科UTF-8的介绍),UTF-8也是按需编码的,比如ASCII字符就还用1个字节表示,而1个字节无法表示的就用2个甚至更多个字节来表示。

Q:为什么有Unicode还要有GB2312和GBK标准?

A: 我查了下,应该是因为GB2312出现的比较早,1980年发布,1981年实施,而Unicode是1990年才发起,1994年发布的。所以在Unicode之前必须有一个标准来表示汉字,就有了gb2312以及后来的GBK。

Python2和Python3的对比

  • Python2: 默认字符集和编码是ASCII。使用str类型来表示bytes,使用unicode类型来表示unicode字符码点。所以对于python2来说,默认的代码里是不能有中文字符的,需要在文件开始处加上# -- coding: UTF-8 -- 来表示文件内容的编码类型。但需要注意的是,比如对于s = “你好"这句,由于默认编码是ASCII,所以实际在执行的时候s的类型其实是str,存储的其实是"你好"的UTF-8的bytes,类型是str。而当遇到需要默认encode的场景的时候,python的做法是首先会先用ASCII的解码器先decode成ASCII的字符串,之后再encode成ASCII的bytes。所以对于"你好” s来说,如果有场景用了默认的编解码,那就会报有ASCII无法识别的字3符,无法解码的异常,因为s存储的是UTF-9的bytes且大于127超出了兼容范围。而对于s = u"你好"这种前面显式加u标识为了unicode类型的情况,如果有默认encode需求时会报encode异常,因为默认是ASCII编码,解码的时候是按照ASCII解的,这中需要显式指定编码类型encode(“utf-8”)。
  • Python3: 默认字符集是unicode,编码是UTF-8。使用str类型表示unicode,使用bytes类型表示字节。这样就很统一了,没有什么歧义。

代码示例

Python2和3

>>> print(len(“你好”))   # Python 2 - str is bytes
6

>>> print(len(u“你好”))  # Python 2 - Add 'u' for unicode code points
2

>>> print(len(“你好”))   # Python 3 - str is unicode code points
2

Python2

# str bytes, need encode to ASCII strings first.
>>> s = "你好"
>>> s.encode("utf-8")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe4 in position 0: ordinal not in range(128)

# Unicode strings, no need to decode first.
>>> s = u"你好"
>>> s.encode()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)

Python3

# strings is by default made of unicode code points
>>> print(len(“你好”)) 
2

# Manually encode a string into bytes
>>> print(len(("你好").encode("utf-8")))  
6

# You don't need to pass an argument as default encoding is "utf-8"
>>> print(len(("你好").encode()))  
6

# Print actual unicode code points instead of characters
>>> print(("你好").encode("unicode_escape"))
b'\\u4f60\\u597d'

# Print bytes encoded in UTF-8 for this string
>>> print(("你好").encode()) 
b'\xe4\xbd\xa0\xe5\xa5\xbd'

引用

https://en.wikipedia.org/wiki/GB_2312
https://en.wikipedia.org/wiki/GB_18030
https://en.wikipedia.org/wiki/GBK_(character_encoding)
https://en.wikipedia.org/wiki/UTF-8
https://en.wikipedia.org/wiki/Unicode

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值