Home  >  Article  >  Backend Development  >  关于Python下的编码问题?

关于Python下的编码问题?

WBOY
WBOYOriginal
2016-06-06 16:22:591073browse

请问哪位大牛能详细而又通俗的解释下,
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
<code class="language-python"><span class="n">In</span> <span class="p">[</span><span class="mi">1</span><span class="p">]:</span> <span class="n">a</span><span class="o">=</span><span class="s">'你好'</span>

<span class="n">In</span> <span class="p">[</span><span class="mi">2</span><span class="p">]:</span> <span class="n">a</span>
<span class="n">Out</span><span class="p">[</span><span class="mi">2</span><span class="p">]:</span> <span class="s">'</span><span class="se">\xe4\xbd\xa0\xe5\xa5\xbd</span><span class="s">'</span>

<span class="n">In</span> <span class="p">[</span><span class="mi">3</span><span class="p">]:</span> <span class="n">b</span><span class="o">=</span><span class="n">a</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="s">'utf-8'</span><span class="p">)</span>

<span class="n">In</span> <span class="p">[</span><span class="mi">4</span><span class="p">]:</span> <span class="n">b</span>
<span class="n">Out</span><span class="p">[</span><span class="mi">4</span><span class="p">]:</span> <span class="s">u'</span><span class="se">\u4f60\u597d</span><span class="s">'</span>

<span class="n">In</span> <span class="p">[</span><span class="mi">5</span><span class="p">]:</span> <span class="nb">type</span><span class="p">(</span><span class="n">b</span><span class="p">)</span>
<span class="n">Out</span><span class="p">[</span><span class="mi">5</span><span class="p">]:</span> <span class="nb">unicode</span>

<span class="n">In</span> <span class="p">[</span><span class="mi">6</span><span class="p">]:</span> <span class="nb">type</span><span class="p">(</span><span class="n">a</span><span class="p">)</span>
<span class="n">Out</span><span class="p">[</span><span class="mi">6</span><span class="p">]:</span> <span class="nb">str</span>

<span class="n">In</span> <span class="p">[</span><span class="mi">7</span><span class="p">]:</span> <span class="n">c</span><span class="o">=</span><span class="n">b</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s">'utf-8'</span><span class="p">)</span>

<span class="n">In</span> <span class="p">[</span><span class="mi">8</span><span class="p">]:</span> <span class="n">c</span>
<span class="n">Out</span><span class="p">[</span><span class="mi">8</span><span class="p">]:</span> <span class="s">'</span><span class="se">\xe4\xbd\xa0\xe5\xa5\xbd</span><span class="s">'</span>

<span class="n">In</span> <span class="p">[</span><span class="mi">9</span><span class="p">]:</span> <span class="n">c</span><span class="o">==</span><span class="n">a</span>
<span class="n">Out</span><span class="p">[</span><span class="mi">9</span><span class="p">]:</span> <span class="bp">True</span>
</code>
善于搜索,参考廖雪峰的博客:字符串和编码 这个你搜网上很多啊。 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/
这篇文章不错~
Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn