• 技术文章 >后端开发 >Python教程

    关于Python下的编码问题?

    2016-06-06 16:22:59原创495
    请问哪位大牛能详细而又通俗的解释下,
    Python2下unicode、utf-8、decode、encode之间的关系。

    我感觉我在这方面的认识还不够清晰,希望大牛们能帮帮忙,谢谢!!

    回复内容:

    py2的编码其实是最最贴近实际的编码形式了。反倒是py3,如果遇到个编码标记错误之类的问题,直接让你自杀……

    先说编码是什么:我们知道计算机里存储任何数据都是存储的二进制,但是一串文字若是当图片那样存储太浪费空间不说,也会难以解析,所以ascii标准码使用了7位二进制标记了128个字符和控制符号。当然7位不利于数据对齐,所以干脆以8位存储,最高位补个0就好,正好一个字节,此即为基础ascii编码。

    但是这128个字符里,虽然包含了常见英文符号和必须的控制符号(比如换行、回车、EOLN、EOF),却对使用其它语言的用户而言没法用,毕竟各家字符不同哇……

    首先是欧系拉丁语系指出,既然一个字节一个字符,只用到7位,那么还有128个编号可以用,于是规定了相应的拉丁语系主要符号,同样单字节表示,这样就用到了多出来的一位,这套编码称之为latin-1

    再往后,大多数其他拼音语言的国家表示,我们不用拉丁文符号,那么把那128个额外字符改成别的符号,映射自己的文字就没问题了。于是出现了多编码页,也就是最初的codepage。

    但是中日韩为首的字形语言系的国家不行啊,你们丫的就几十个符号,可中文之类光常用字就好几千啊……于是针对中文出现了codepage936/gb2312,通过两个字节表示一个汉字,其中包含数千常用字,并且规定最高位为0的部分完全兼容ascii,但是若最高位为1,则必须是两个字节连续出现,用以表示一个汉字——随后还出现了GBK,规定的字符更多,兼容gb2312,同样是个双字节纪录。

    然而有两件事情形成了阻碍:一是中文博大精深,汉字实在太多,算上生僻字,两个字节其实也不够用;另一方面,在GB系编码下,所有双字节字符都会被解释成汉字,因此最多做到英汉混排,多语言没戏,同时还会影响到诸如网络传输等等场景,因为同样的双字节二进制数据,对应GBK中文与对应的日文韩文显然不同,这就必须带着编码类型跑,稍不注意就不知道是个啥语言的玩意。

    于是出现了unicode,是ANSI标准下的多国语言文字编码。unicode使用32位二进制表示每一个字符,且任意语言任意符号都有独立编码,这样就可以做到使用一套编码同时处理多种不同语言。

    unicode是个编码方式,只涉及编号,并不管传输和存储。针对需求,unicode产生了若干传输用编码,其中比较普及的有utf32,utf16和utf8。utf32是每字符32位固定编码,完整映射unicode原编码而不做改变(当然,规定了一下传输时的端序问题);utf16则是最少16位最多32位,属于变长unicode传输方案,以实现对部分codepage的兼容;而utf-8则是最小8位最大32位的编码,变长,且英文部分完全兼容ascii。由于省空间及ascii兼容这两点,使得改用utf8代价最小,才成为了主流。

    python2里,与编码有关的有三个部分:

    一是源代码识别问题。原本python解释器纯粹把源码使用ascii编码进行解析生成语法树。考虑到源码里可能存在其他语言的字符串量,提供了setdefaultencode接口,但是非常容易引发各类问题。PEP263指出在文件第一行或者第二行(仅限第一行为Unix脚本标注的情况下)写入特殊格式的注释# coding:xxx可以指定解释器解释源码时使用的字符编码。

    第二部分则是内置类型转换:python2里的str类,其实是个不存储编码信息的类型。也就是说它把内容二进制按照逐个字节来处理和比对、运算。str类型的「字符串」如果拿来迭代一下,会直接拆成一个个字节来处理。但是,一旦我们需要对非单字节编码的单个字进行处理的时候,python只提供了一个类型来解决问题,即unicode类(注意,实质上py里这个类是utf8进行内存存储的,并不是utf32/unicode原编码),所以常常需要相互转换,将用到encode/decode两个方法。原则上是,decode方法是将一个str按照指定编码解析后转换为unicode,encode方法则是把一个unicode对象用指定编码表示并存储到一个str对象里。

    第三点是输入输出。Python2的print的实质是将str里的东西输出到PIPE,如果你print的是一个unicode对象,它会自动根据LOCALE环境变量进行encode之后变成str再输出。然而一般在Windows上都没有设置locale环境变量,py2就按照默认的ascii编码进行处理,于是对中文自然就编码错误了。解决方法是手动encode成对应的输出端可接受的编码后输出。win下一般都是gbk,linux下一般都是utf8

    py3中的str则是unicode,bytes才类似于原str,默认代码解析用utf8,默认输出编码也是utf8。

    ASCII 、unicode 是字符集,utf-8是字符集的编码方式。

    utf-8 是 unicode 字符集一种编码方式。



    如果你不指定py文件的编码方式,程序默认按照 ASCII 字符集来解码。所以需要声明文件编码方式。

    decode 和 encode
    In [1]: a='你好'
    
    In [2]: a
    Out[2]: '\xe4\xbd\xa0\xe5\xa5\xbd'
    
    In [3]: b=a.decode('utf-8')
    
    In [4]: b
    Out[4]: u'\u4f60\u597d'
    
    In [5]: type(b)
    Out[5]: unicode
    
    In [6]: type(a)
    Out[6]: str
    
    In [7]: c=b.encode('utf-8')
    
    In [8]: c
    Out[8]: '\xe4\xbd\xa0\xe5\xa5\xbd'
    
    In [9]: c==a
    Out[9]: True
    
    善于搜索,参考廖雪峰的博客:字符串和编码 这个你搜网上很多啊。 unicode是codepoint 就是一个抽象的\uxxx 代表一个字符。 而utf-8是unicode的一种,用x个字节表示一个抽象的codepoint \uxxx. 所以utf-8是实际的字节串,而unicode是抽象. 你可以把抽象的unicode encode(编码)成utf-8. 也可以把实际的utf-8 解码回unicode. 说了这么多,然并ruan... 请搜索“将python2中汉字会出现乱码的事一次性说清楚”
    看看! 用 python3 吧,最近用 python, 已经被2.x 的编码问题搞的要怀疑人生了,真是坑死人。。 nedbatchelder.com/text/
    这篇文章不错~
    声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn核实处理。
    上一篇:打印日志 (log) 是比单步跟踪 (debugger) 更好的 Python 排错手段吗? 下一篇:Python 为什么不解决四舍五入(round)的“bug”?
    Web大前端开发直播班

    相关文章推荐

    • 详细介绍Python之Pandas知识点• Python数据类型详解之字符串、数字• Python归纳总结之json标准库• 详细讲解Python之Seaborn(数据可视化)• 完全掌握Python数学相关模块

    全部评论我要评论

  • 取消发布评论发送
  • 1/1

    PHP中文网