在 Python 尤其是 Python2 中,编码问题是困扰开发者尤其初学者的一大问题。什么 Unicode/UTF-8/str ,又是 decode/encode 的,搞得人头都大了。其实不然,这有点类似 Java 中 java.io 包一样,看似庞大难懂,但是可以非常精细地定制需求。

编码

计算机只可以存储和处理二进制数据,所以从文字到计算机可以识别的二进制之间需要一道对应关系。于是便有了ASCII(American Standard Code for Information Interchange,美国标准信息交换代码),ASCII使用7位二进制数标记了128(2**7)字符(符号、字母、控制符等),由于1byte=8bit,所以干脆最高位补个0,凑够8位以方便计算和处理。

接着,拉丁语系的技术宅们发现,这128个字符的高位空着的,那么干脆用来表示拉丁语系的主要符号吧,还是使用单字节,但是可以表示的字符数量增加了一倍。这套编码叫做latin-1(iso-8859-1)。

这些宅男们没有想到,区区一个字节256个符号,对于东亚国家来讲,简直呵呵了。拿中文为例,仅常用字符就几千个,于是中国国家标准总局制定了一套中文编码——GB2312。GB2312通过两个字节表示一个汉字,且最高位为0的部分兼容ASCII,最高位为1的部分则通过连续的两个字节表示一个中文字。后来又出现了兼容GB2312的GBK编码。

到这里,依然面临了一个问题:GB2312或者GBK编码中,仅可以表示汉字和英文字符,无法做到多语言文字同时表示。这时候,Unicode(又称万国码)出现了。Unicode采用32位二进制(4字节)表示一个字符,这样便可以一套编码对应多种不同语言。Unicode是一种编码,它的作用是指定字符到二进制数之间的对应关系。但是对于存储和传输,Unicode有几种不同的实现,比较常用的是UTF-8、UTF-16、UTF-32。UTF-32中,每个字符固定占4字节,按照Unicode编码完全映射。而UTF-8和UTF-16则属于变长编码,分别使用最少1个(UTF-8)或2个(UTF-16)字节到最多4个字节来编码。

Python源码的编码

Python2中,如果在源码首行(或在指定sha-bang时的第二行)不显式指定编码,则无法在源码中出现非ASCII字符。这是由于Python解释器默认将源码认作ASCII编码格式。PEP263(点击这里查看)中约定,可以通过如下方式之一来声明源码的编码格式:

# coding=<coding name>

# or

# -*- coding: <encoding name> -*-

# or

# vim: set fileencoding=<encoding name> :

Python中的编码

Python中有两个常用的由basestring派生出来的表示字符串的类型:str,unicode。其中,str类似于C中的字符数组或者Java中的byte数组,事实上你可以将它理解为一个存储二进制内容的容器,str不存储编码信息,如果对str类型的字符串迭代的话,则会按照其在内存中的字节序依次迭代,意味着如果这个字符串存储的是多字节字符(Unicode/GBK等),则会截断这个字符,演示如下:

而对于unicode类型,Python在内存中存储和使用的时候是按照UTF-8格式,在代码中的表示为字符串前加u,如:

而unicode与str之间的转换,则用到了encode和deocde方法。decode表示将一个(str)字符串按照给定的编码解析为unicode类型,encode则表示将一个unicode字符串按照指定编码解析为字节数组(str):

文件读写

内置的open函数打开文件时,read方法读取的是一个str(私以为叫做字节数组更合适),如果读取的是其它编码的文字,则需要decode之后再做使用。

对于使用open函数打开文件之后的写操作(多字节编码的字符串),则需要将需要写入的字符串按照其编码encode为一个str,如果直接写入,则会引发如下错误(如果在代码中加入了encoding声明,则会按照声明的编码格式encode后写入):

除此以外,codecs模块也提供了一个open函数,可以直接指定好编码打开一个文本文件,那么读取到的文件内容则直接是一个unicode字符串。对应的指定编码后的写入文件,则可以直接将unicode写到文件中。通过codecs.open可以避免很多编码问题:

建议

对于Python代码中避免遇到编码问题,有一些小建议:

  • 字符编码声明:在代码开头声明编码格式

  • 使用codecs的open函数处理文本文件

  • 尽可能使用unicode而不是str:在所有字符串的引号前加u

Python 2 中的编码的更多相关文章

  1. python语言中的编码问题(续)

    上文提到了python开发中非常重要的两处设置. 一个是编解码器的默认设置defaultencoding >>> import sys >>> sys.getdef ...

  2. python语言中的编码问题

    在编程的过程当中,常常会遇到莫名其妙的乱码问题.很多人选择出了问题直接在网上找答案,把别人的例子照搬过来,这是快速解决问题的一个好办法.然而,作为一个严谨求实的开发者,如果不从源头上彻底理解乱码产生的 ...

  3. 聊聊python 2中的编码

    为什么需要编码: 计算机可以存储和处理二进制,那么从文字到计算机可以识别的二进制之间需要对应的关系,于是便有了ASCII,ASSCII使用7位字符,由于1byte=8bit,所以最高位补一个0,使用8 ...

  4. python 2 和python 3 中的编码对比

    在 Python 中,不论是 Python2 还是 Python3 中,总体上说,字符都只有两大类: 通用的 Unicode 字符: (unicode 被编码后的)某种编码类型的字符,比如 UTF-8 ...

  5. day06 python 3中的编码

    #python2 和 python3 的一些区别 ''' #python2 print('aaa') print'aaa' range() xrange()生成器 raw_input() #pytho ...

  6. python中的编码问题:以ascii和unicode为主线

      1.unicode.gbk.gb2312.utf-8的关系 http://www.pythonclub.org/python-basic/encode-detail 这篇文章写的比较好,utf-8 ...

  7. python中的编码声明

    python中的第一行,目的就是指出,你想要你的这个文件中的代码用什么可执行程序去运行它,就这么简单 #!/usr/bin/python 相当于写死了 python 路径(是告诉OS执行这个py时,调 ...

  8. python unicode 转中文 遇到的问题 爬去网页中遇到编码的问题

    How do convert unicode escape sequences to unicode characters in a python string 爬去网页中遇到编码的问题 Python ...

  9. python中的编码与解码

      编码与解码 首先,明确一点,计算机中存储的信息都是二进制的   编码/解码本质上是一种映射(对应关系),比如‘a’用ascii编码则是65,计算机中存储的就是00110101,但是显示的时候不能显 ...

随机推荐

  1. matlab里textread出现错误“Trouble reading floating point number from file (row 1, field 1)”

    matlab里textread出现错误“Trouble reading floating point number from file (row 1, field 1)” 解决办法:traindata ...

  2. ABAP字符串操作 截取字符长度 取位数

    ABAP字符串操作   ABAP對字串的操作方法與其他語言的操作有較大差別,以下是較常用的對字串操作的方法: 1. 字串的連接:CONCATENATEDATA: t1 TYPE c LENGTH 10 ...

  3. underScore学习1:匿名函数中call(this)的作用

    匿名函数中(function(){}).call(this) 中的.call(this) 有什么用? 我们都知道,.call()可以改变函数执行时的context,即this的指向,源码中的.call ...

  4. 生成元(Digit Generator,ACM/ICPC Seoul 2005,UVa 1583)

    #include<cstdio>#include<cstdlib>#include<cstring>using namespace std;int t, n, a, ...

  5. Linux 虚拟机性能监控

    性能监控工具 perf kvm 为了在主机中使用perf kvm,您必须访问/ proc / modules和/ proc / kallsyms文件."复制/ proc文件从guest虚拟机 ...

  6. Oracle跨库访问数据表-DBLINK

    1:创建DBLINK(USING后面的连接字符串就是要访问的那个数据库的连接字符串) CREATE DATABASE LINK linkName CONNECT TO userName IDENTIF ...

  7. use ContourPlot-使用ContourPlot

    use ContourPlot to draw implicit function graphics 使用ContourPlot 画隐函数图像 for example $x^{3}+y^{3}-3xy ...

  8. history对象 back() forward() go() 和pushState() replaceState()

    History(Window.history对象)对象保存着用户上网的历史记录.处于安全方面的考虑,开发人员无法得知用户浏览过的URL,但是借由用户访问过的页面列表,同样可以在不知道实际URL的情况下 ...

  9. JAVA中数组总结(课堂总结)

    数组的特点: Arrays(数组)一种简单的数据结构元素具有相同的数据类型一旦创建之后,尺寸保持不变元素在内存中连续分布例子一:按引用与按值传递的示例源代码: // PassArray.java // ...

  10. android ScrollView中嵌套listview listview可点击处理,可展开

    public class MyListView extends ListView { public MyListView(Context context, AttributeSet attrs, in ...