摘要:最近使用处理一些网络相关的问题,被相关的一系列编码问题搞得一头雾水。与接下来是中对于字符串的处理。中的和在中,其类型规定了底层的数据结构,是位整数串,也即跟语言中的字符串类似。这些问题在中得到解决。
最近使用 Python 2 处理一些网络相关的问题,被 Unicode, String 相关的一系列编码问题搞得一头雾水。在这里整理一下相关的概念吧。
ASCII Unicode UTF8首先是与 Python 无关的编码问题。在这里理清楚这几个常见的名词:ASCII, Unicode, UTF8 之间的关系。
我们知道,为了使用计算机处理字符,需要将字符编码为数字。对于英文字符,128 个数字就够了,其中最常见的英文字符编码方案就是 ASCII,该方案规定了使用 7 位二进制数编码英文字符的方案。
对于非英文字符,特别是汉语这种有超大字符集的语言,需要需要一个很大的编码表将字符编码为数字。竞争之后现在通用的方案是 Unicode,该方案的目标是覆盖所有人类语言符号。也就是说,Unicode 定义了一个从任意字符到数字的一一映射关系。
对于 ASCII 而言,一个字符(使用 7 位编码)占用一个字节(8 位)就够了,可以简单地用这个字节表示一个无符号整数来代表编码,浪费并不大。但是对于 Unicode 而言,由于码表太大,需要很多字节才能表示一个 Unicode 编码数字,而且 Unicode 是一个成长中的项目,其码表不断扩充。因此,如何用字节表示 Unicode 编码数字就成了一个问题,UTF-8 就是解决这个问题的方案之一。该方案是一种变长方案,使用不定长的字节表示一个数字。方案对于包含在 ASCII 码表中的字符只使用 1 个字节进行编码,对于非英语拼音语言符号通常使用 2 个字节编码,汉字通常使用 3 个字节进行编码。
如果接触过信息论,可以很容易的理解变长编码是如何做到的。如果读者没有接触过信息论,这里展示一种简陋的变长编码方案,方便读者理解。
第一个字节总是使用无符号整数表示。当数值位于 [0,254] 中时,这个字节的代表的数值就是编码的数值。但当数值是 255 时,不表示这个数字是 255,而是表示这个数字加上之后两位(16 bit) 代表的数之后才是编码的数字,于是这个边长方案能使用 1~3 字节编码 [0, (2 ^ 16 - 1) + (2 ^ 8 - 1)] 之间的数字。
总结而言就是,Unicode 是一个字符到数字映射表,而 UTF-8 是数字到字节的编码方案。ASCII 由于只使用一个字节,通常不太强调其数字的编码方案。
Python 与 Unicode接下来是 Python 中对于字符串的处理。
python 2 中的 str 和 unicode在 Python 2 中,其 str 类型规定了底层的数据结构,是 8 位整数串,也即跟 C 语言中的字符串类似。而 unicode 类型是整数串,并不规定整数的位数或保存方式。unicode.encode() 方法在指定一种编码方式之后返回一个 str 对象,即为这个 unicode 字符串在该编码方式之下的字节表示。
用例子说明这个问题:
# python 2 us = u"你好" assert(len(us) == 2) # us 是整数串,共有两个整数,代表两个字符 s = us.encode("utf8") assert(len(s) == 6) # 使用 utf8 编码之后,每个汉字用 3 个字节表示,共 6 个字节
仅仅是这样,并不会引起太大的混淆。一个问题是 python 2 的字符串是可以被初始化为非英文字符的:
# python 2 s = "你好" assert(len(s) == 6)
这种情况下解释器会自动完成编码工作,具体编码方式笔者认为用户不应该知道,而且笔者认为这种用法可能不是一种很好的用法。
更加糟糕的是,python 2 的 print 语句表现有时候会有些神奇:
# python 2 print "你好" # 得到 你好 print u"你好" # 得到 你好 print ["你好"] # 得到 ["xe4xbdxa0xe5xa5xbd"] print [u"你好"] # 得到 [u"u4f60u597d"]
也就是,只有当直接 print str 或者 print unicode 的时候能够正常输出中文,其他情况下, print [str] 会输出 "str", print [unicode] 会输出 u"unicode"。这些打印结果看上去会让人怀疑没有解码,实际上是 print 语句的行为而已。
python 3 中的 byte 和 str在 python 2 中,str 是一种底层数据结构,类似于比特串,但 string 这个英语单词的意思是字符串,容易引起混淆,如 unicode.encode() 返回值是一个 str,逻辑上并不恰当。
这些问题在 python 3 中得到解决。python 2 中的 str 类型相当于 python 3 中的 bytes 类型, bytes 这个名字明确的指出这是字节串,并且不指定字节串代表什么东西。而 python 3 中的 str 类似于 python 2 中的 unicode 类型, 不再指定底层编码规则。str.encode() 返回一个 bytes 类型也更加符合逻辑。
用例子说明:
# python 3 s = "你好“ assert(len(s) == 2) bs = s.encode("utf8") assert(len(s) == 6)
Python 3 中的 print 函数一般总是可以正常打印 str,而不是输出码值。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/45545.html
摘要:而他们的中文释义,就是对新手的最大陷阱编码。而码,也就是美国信息交换标准码,年发布,位字符编码中影响最大的一种。 编码,还是编码! python2的直钩——编码异常 当你用python打开一篇中文文档,准备读取里面的数据开始实验...当你处理好你的数据,打算打印出易于阅读的结果给boss检查...甚至当你刚刚开始编写自己的代码,就写了一句话... text = 什么鬼 只要你开始运行自...
摘要:预告一下,下一篇你真的知道的字符串怎么用吗将会展开介绍,敬请期待字符串序列是一种不可变序列,这意味着它不能像可变序列一能,进行就地修改。例如,在字符串的基础上拼接,得到字符串,新的字符串是一个独立的存在,它与基础字符串并没有关联关系。 showImg(https://segmentfault.com/img/bVbjGGr?w=6016&h=4000); 在《详解Python拼接字符串...
摘要:预告一下,下一篇你真的知道的字符串怎么用吗将会展开介绍,敬请期待字符串序列是一种不可变序列,这意味着它不能像可变序列一能,进行就地修改。例如,在字符串的基础上拼接,得到字符串,新的字符串是一个独立的存在,它与基础字符串并没有关联关系。 showImg(https://segmentfault.com/img/bVbjGGr?w=6016&h=4000); 在《详解Python拼接字符串...
阅读 752·2023-04-26 00:30
阅读 2644·2021-11-23 09:51
阅读 1009·2021-11-02 14:38
阅读 2515·2021-09-07 10:23
阅读 2199·2021-08-21 14:09
阅读 1232·2019-08-30 10:57
阅读 1572·2019-08-29 11:20
阅读 1099·2019-08-26 13:53