欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

彻底搞清楚unicode和utf8编码

程序员文章站 2022-07-14 19:14:34
...

彻底搞清楚unicode和utf8编码

一:字符串编码

我们知道,计算机是以二进制为单位的,也就是说计算机只识别0和1,也就是我们平时在电脑上看到的文字,只有先变成0和1,计算机才会识别它的意思。这种数据和二进制的转换规则就是编码。计算机的发展中,有ASCII码,GBK,Unicode,utf-8编码。

  1. 计算机只能处理数字,文本转换为数字才能处理。计算机中8bit作为一个字节(byte),所以一个字节能表示最大的数字就是255
  2. 计算机是美国人发明的,所以一个字节可以表示所有字符,所以ASCII(一个字节)编码就成为美国人的标准编码。ASCII 编码,它仅仅对 10 个数字、26 个大小写英文字母以及一些特殊字符进行了编码。ASCII 码做多只能表示 256 个符号,每个字符只需要占用 1 个字节。
  3. 但是ASCII处理中文明显是不够的,中文不止255个汉字,所以中国制定了GB2312编码,用两个字节表示一个汉字。GB2312还把ASCII包含进去了,同理,日文,韩文等等上百个国家为了解决这个问题就发展了一套字节的编码,标准就越来越多,如果出现多种语言混合显示就一定会出现乱码
  4. 于是unicode出现了,将所有语言统一到一套编码里
  5. 看一下ASCII和unicode编码:
    1)字母A 用ASCII编码十进制是65, 二进制 0100 0001
    2)汉字“中”已经超出了ASCII编码的范围,用unicode编码20013,二进制 0100 1110 0010 1101
    3)A用unicode编码只需要前面补0,二进制就是 00000000 0100 0001
  6. 乱码问题解决了,但是如果内容全是英文,unicode编码比ASCII需要多一倍的存储空间,同时如果传输需要多一倍的传输。
  7. 所以出现了可变长的编码 utf-8,把英文变长一个字节,汉字3个字节。特别生僻的变成 4-6字节,如果传输大量英文,utf8作用就很明显了。

二:Python中的encode()与decode()

Python2里的str是十六进制表示的二进制编码,unicode是一个字符:通俗点来说就是Python2里的str类型是一堆二进制编码,如果不知道是什么字符集那么你除了一堆十六进制数什么都看不出来(当然平时你使用的工具都是能看到的,因为工具已经做了转码),通过decode可以将其按固定的字符集解码,生成unicode字符。

  1. decode英文意思是 解码,encode英文原意 编码
  2. 字符串在Python内部的表示是unicode编码,因此,在做编码转换时,通常需要以unicode作为中间编码, 即先将其他编码的字符串解码(decode)成unicode,再从unicode编码(encode)成另一种编码。
  3. decode的作用是将其他编码的字符串转换成unicode编码,如str1.decode(‘gb2312’),表示将gb2312编码的字符串str1转换成unicode编码。
  4. encode的作用是将unicode编码转换成其他编码的字符串,如str2.encode(‘gb2312’),表示将unicode编码的字符串str2转换成gb2312编码。

总得意思:想要将其他的编码转换成utf-8必须先将其解码成unicode然后重新编码成utf-8,它是以unicode为转换媒介的 如:s=‘中文’ 如果是在utf8的文件中,该字符串就是utf8编码,如果是在gb2312的文件中,则其编码为gb2312。这种情况下,要进行编码转换,都需要先用 decode方法将其转换成unicode编码,再使用encode方法将其转换成其他编码。通常,在没有指定特定的编码方式时,都是使用的系统默认编码创建的代码文件

decode: str to unicode,decode的输入必须是str类型,输出一定是unicode类型
str.decode(encoding='UTF-8',errors='strict')
​
encode: unicode to str,encode的输入必须是unicode类型,输出一定是str类型
unicode_char.encode(encoding='gbk',errors='strict')

彻底搞清楚unicode和utf8编码

# 例如下例:python2环境下的windows cmd窗口
>>> a='你好'
>>> a.decode('utf-8')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Python27\lib\encodings\utf_8.py", line 16, in decode
    return codecs.utf_8_decode(input, errors, True)
UnicodeDecodeError: 'utf8' codec can't decode byte 0xc4 in position 0: invalid continuation byte
# 错误的原因是这里的“你好”字符是cp936编码(相当于gbk),utf-8属于非ANSI体系的编码,“你好”的gbk二进制码不符合unicode体系的编码规则因此报错。
>>> print a.decode('gbk'),type(a.decode('gbk'))
你好 <type 'unicode'>
# 这样就可以啦,既然a是gbk编码的str那么按gbk进行decode解码,自然能得到unicode的你好字符。

同样在Python3中str调用decode()方法会遇到: AttributeError: ‘str’ object has no attribute ‘decode’ 。
这是因为python3中表示文本的只有一种类型了,那就是str,你以为这是python2里的那个str吗?No! 这个str是python2中的unicode类型…
那么原来的str哪里去了?被命名为bytes类型了,decode方法也随之给了bytes类型,encode给了str类型。
彻底搞清楚unicode和utf8编码
这样做的好处是:

在Python2中str和unicode都有decode,encode两种方法,但是字符集参数不设置正确的话,函数经常报错,文本能否正确流通取决于大家是否清楚输入编码的字符集,这对于全球化的网站来说是个巨坑,而在Python3中无论你输入什么字符,统一都是str类型的(也就是python2里的unicode类型),通过bytes和str类型的分离将decode,encode这两种方法分离,encode函数不会出错,因为编码与字符集是绑定的,你可以随意将unicode字符转化为任意ANSI体系字符集的bytes类型,此时在已知ANSI字符集的情况下,你对bytes类型的decode转码一定不会出错。通过这种方式就避免了python2中输入str类型带来的编码混乱问题。

[aaa@qq.com ~]# python3
Python 3.6.5 (default, Apr  9 2018, 17:15:34)
[GCC 4.4.7 20120313 (Red Hat 4.4.7-4)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> a='你好'
>>> type(a)
<class 'str'>
>>> a.encode('gbk')
b'\xc4\xe3\xba\xc3'
>>> type(a.encode('gbk'))
<class 'bytes'>
# 通过encode方式我们可以把unicode字符转为任意字符集的bytes类型,这种bytes类型可以通过decode()来重新转为unicode。