给自己与初学者关于decode,encode的建议(啥utf-8,GBK)。
2021-01-18更新
参考链接:https://www.bilibili.com/video/BV1Sp4y1U7Jr?p=160
最近一直空的时候看一些老男孩的教学视频,对基础的Python知识查漏补缺。
刚看到字符的解码与编码问题,记录一些我自己的学习感悟吧。
当我们在终端输出看到的,包括一些文本编辑器看到的,理论上面都是Unicode的字符串形式。
当我们打开一个文本文件的时候,必须用一直指定的编码形式来解码文件中的数据,你可以用各种不同的编码集,但正确的应该是你写入硬盘的时候的编码集。
说到底,文字还是给人看的,计算机最终的保存还是二进制的文件,在20世纪90年代,为了创造一种能包含全球文字的字符集出现了,那就是Unicode。
计算机启动后,内存中应该运行这个Unicode字符集的类似与mapping的程序,这是一个大型的中转站,因为现在的计算机必须要基本的需求,能够显式各种文字。
所以Unicode的每一个字都又对应的不同字符集的对应的编码,可以理解为Unicode的每一个字为key,不同的字符集的编码为value,而且是一对多的。
好比一个中文字"好"的Unicode编码为'\u597d',他针对不同的字符集有着不同的对应编码。
我说的是假如:GBK下面对应的是\x1122,这样的话,如果通过GBK的方式保存在电脑的话数据就是\x1122,但打开的时候通过GBK解码,会找到对应Unicode的编码,从而显式正常的数值。
按照现在的趋势来看,后续的任何文本操作都应该保存为utf8格式,因为utf8是Unicode的一种转换表达,简单理解utf8与Unicode的编码存在一一对应的关系。
但另外的字符集可能就会出现问题,中国的字符集不能编码日文,从而不能保存有日文的信息。
对于不能理解字符集相关知识的朋友,记住一点就够了,就是从现在开始,任何的文本文件都用utf8进行操作与保存就对了。在计算机内部Unicode的暂存是因为给另外的编码集当中转站使用。
学了不少时间了,对于字符串的编码与解码总算有了一些认识。
记录一些自己的想法。
首先,在Python3里面,我们的str类型,相当于Python2的中unicode。
>>> name = '四店' >>> name '\xe5\x9b\x9b\xe5\xba\x97' >>> uname = name.decode('utf-8') >>> print name 四店 >>> print uname 四店 >>> uname u'\u56db\u5e97' >>> type(uname) <type 'unicode'> >>> type(name) <type 'str'>
上面的是在python2中运行的结果,可以看到终端模式下,输入字符串对象只会出来对象的字节码数据,只有在print输出的时候,才出现对应的文字。
但在Python3中完全不一样了,py3的str就是py2的unicode
In [663]: name = u'\u56db\u5e97' In [664]: name Out[664]: '四店' In [665]: uname = name.encode('utf8') In [666]: uname Out[666]: b'\xe5\x9b\x9b\xe5\xba\x97' In [667]: print(name) 四店 In [668]: print(uname) b'\xe5\x9b\x9b\xe5\xba\x97'
在这里可以看到,我们赋值给name的unicode的字符标识,但无论是终端还是print输出,name一直是四点了。
name明显是str模式,所以证明了前面说的。
后面流畅的Python我会记录自己的更加详细对与解码,编码的理解。
其实想通了感觉也就那么回事,网上好多资料,基本都是一大抄。
我最后稍微总结一下。unicode就是一份超级大字典,全世界所有的文字都有,所以Python终端显示用unicode蛮好
但unicode的对应表,很多人觉的传输数据的时候不好,就搞出来了utf-8,utf-16,utf-32,这个也是一份映射表。
假如在unicode里面,每个文字的名字相当与码位,utf-8,utf-16就好比编号。
比如"好"的unicode为u'\u597d',utf-8为'\xe5\xa5\xbd'
这个一对一对应的,就是说,unicode里面的每一个字符都可以找到utf-8的对应字节序(通俗讲就是编号)。
所以大家应该用utf-8。
再来说一些地方与国家的编码,比如中国的gbk,gbk包含了全部的中国字与字节码的映射关系,可以想象成这是一本,中国的地方字典。
In [669]: name Out[669]: '四店' In [670]: bytes(name,encoding='gbk') Out[670]: b'\xcb\xc4\xb5\xea'
当我们在encode的时候,首先先拿gbk对照表里面的字来对比需要解码的字,比如第一个四字,找到了它的序号为\xcb\xc4,然后对编号进行输出。
所以这个很容易造成问题,你如果给一个他字符集没有的字,找了老半天才找到。
In [679]: '\u20ac'.encode('gbk') --------------------------------------------------------------------------- UnicodeEncodeError Traceback (most recent call last) <ipython-input-679-90f6ff568b6b> in <module> ----> 1 '\u20ac'.encode('gbk') UnicodeEncodeError: 'gbk' codec can't encode character '\u20ac' in position 0: illegal multibyte sequence In [680]: '\u20ac' Out[680]: '€'
就报错了,话说gbk的字符集还是蛮厉害了,输入了日本字,意大利的字,基本都有。
但对于utf-8只要是unicode的字符,他都能编码
In [680]: '\u20ac' Out[680]: '€' In [681]: '\u20ac'.encode('U8') Out[681]: b'\xe2\x82\xac'
所以再次推荐大家以后都用utf-8这样的话,以后里面的decode,encode的ignore参数都可以不用了。
这里还有一份老外写的参考链接:https://pycoders-weekly-chinese.readthedocs.io/en/latest/issue5/unipain.html
还行吧,反正我没咋看懂,应该有很多py2的说明,py2基本没啥节操过。
前面写的我就不删除了,从流畅的Python书中指出,Python内置100多种字符编码。
我的理解就是,当给你一个字符假如是"我",Python的100多种解码器中能找到"我"的对应的字节序列是不一样的。
你通过编码的方式把unicode中的"我"转换成字节序列,可以是2字节,也可能是3字节。
可以用于计算机的存储,或者网络的传输,但机器看的懂的,人看不懂,当需要人看的时候,你又需要用同样的方式把机器的字节序列装换成人看的懂的。
这个就是解码。你用什么编码的,就必须用什么解码,其实有了utf8,另外的编码方式真的应该淘汰了。
解码以后就是unicode了,你可以把unicode想象成就是文字。
但unicode变成文字是在哪里实现,又是如何实现的,网上的资料比较少。所以我只能把unicode想象成文件了,
因为你编码的时候就是对unicode进行编码。
2020年12月4日补充
一段时间的学习与成长,Python网络编程书中说到Python的字符串(character)包含了Unicode字符。以前一直对这个不是很懂,很多书籍解释了,可能是翻译问题,或者我理解问题,不能很好的理解Unicode与Python中的字符串的意思。我现在的理解,就是Python的字符串,就是一堆Unicode。当你在Python的编辑器环境下,只要看到了字符串内有\u形式的字符,就会通过Unicode字符表找到对应码点(code point)的字符
这里一些记录:https://www.zhihu.com/question/26921730/answer/1610972540