ホームページ  >  記事  >  バックエンド開発  >  关于Python下的编码问题?

关于Python下的编码问题?

WBOY
WBOYオリジナル
2016-06-06 16:22:591143ブラウズ

请问哪位大牛能详细而又通俗的解释下,
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/
这篇文章不错~
声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。