聊聊Pyhon的encodings


类型:Python,创建时间:Jan. 1, 2012, 9:15 p.m.

标题无“转载”即原创文章,版权所有。转载请注明来源:http://hgoldfish.com/blogs/article/56/。

我经常用Python做一些字符串处理,一直以为只有str类型有decode()方法,而unicode类型没有,只有unicode类型有encode()方法而str类型没有。后来才突然注意原来这两种类型都有这两个方法,只是用了可能会出错。比如:

u"国将不国".decode("gbk")
"国将不国".encode("gbk")

在Windows下通常会报错。既然如此,为啥给这两种类型都安上decode()encode()呢?疑问疑问!

decode()encode()所支持的编码名字可以在Python的encodings包下找到,路径一般是:

C:\Python26\Lib\encodings
/usr/lib/python2.6/encodings

其中可以找到gbk,utf-8,big5编码。还有一个aliases.py,里面记录了各种编码的别称,比如下面三条语句等价:

u"国将不国".encode("utf-8")
u"国将不国".encode("u8")
u"国将不国".encode("utf8")

再仔细找一找,发现这几个编码挺有意思的:

base64 bz2 hex idna punycode quopri uu
raw_unicode_escape rot_13 string_escape undefined unicode_internal utf_8_sig zlib
  • base64编码,顾名思义,它相互转换普通的字符串与base64字符串:

    >>> "国将不国".encode("base64")
    'ufq9q7K7ufo=\n'
    >>> print 'ufq9q7K7ufo=\n'.decode("base64")
    国将不国
    
  • bz2, zlib编码则分别使用bz2, zlib两种压缩算法对字符串进行压缩与解压缩:

    >>> ("f"*1024*1024).encode("bz2")
    'BZh91AY&SY\x99C\xc0+\x00\x08\nA\x00\x80\x04
    

    x01x00x00x08 x000xccx05Ixeaqx06x01@\x1e.\xe4\x8ap\xa1!2\x87\x80V' >>> print len('BZh91AY&SY\x99C\xc0+\x00\x08\nA\x00\x80\x04\x01 \x00\x00\x08 \x000\xcc\x05I\ xeaq\x06\x01@x1e.xe4x8apxa1!2x87x80V'.decode("bz2")) 1048576

    这里str.decode()str.encode()两个方法都用到了。原来如此!

  • hex编码将字符串转换成十六进制形式:

    >>> '国将不国'.encode('hex')
    'b9fabdabb2bbb9fa'
    >>> print 'b9fabdabb2bbb9fa'.decode("hex")
    国将不国
    

    ps:之前我还傻傻地写过tohex(s)函数,现在才发现原来我重新发明了轮子

  • idnapunycode据说用于支持Internationalized Domain Names。中文域名?呼唤大牛解答。

  • quopribase64经常相提并论,因为它们经常用于邮件的编码。最早的Email系统不大支持非ascii字符集。在发送中文邮件的时候,要使用quopri编码或者base64编码先处理一下。比如:

    >>> "国将不国"
    '\xb9\xfa\xbd\xab\xb2\xbb\xb9\xfa'
    >>> "国将不国".encode("quopri")
    '=B9=FA=BD=AB=B2=BB=B9=FA'
    

    quopri编码实际上就是hex编码的变形。与base64相比较,使用quopri编码转换后的文本一般会比较大一点。不过,如果邮件里ascii占比较大的比例,即使对方的邮件客户端很古老,使用quopri编码也很容易看清楚文本。

  • raw_unicode_escapestring_escape用于将字符串转换成"程序员的写法",先看一下repr()函数怎么样处理字符串:

    >>> print repr(u"国将不国")
    u'\u56fd\u5c06\u4e0d\u56fd'
    >>> print repr("国将不国")
    '\xb9\xfa\xbd\xab\xb2\xbb\xb9\xfa'
    

    这两种编码与repr()类似:

    >>> print u"国将不国".encode("raw_unicode_escape")
    \u56fd\u5c06\u4e0d\u56fd
    >>> print "国将不国".encode("string_escape")
    \xb9\xfa\xbd\xab\xb2\xbb\xb9\xfa
    

    差别在于没了引号与前缀'u'。输出结果都是str类型。

    与上面两种编码对比的是unicode_internal,它用于将字符串转换成"机器的写法",说白了就是把存储unicode字符串的内存拷贝出来:

    >>> u'国将不国'.encode('unicode-internal')
    '\xfdV\x06\\\rN\xfdV'
    

    timeit测试了一下,貌似raw_unicode_escapeunicode-internal的速度相差不大,虽然unicode-internal会快一点点。

  • undefined编码是一种总给你报错的编码。

    >>> "国将不国".encode("undefined")
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "C:\Python26\lib\encodings\undefined.py", line 19, in encode
        raise UnicodeError("undefined encoding")
    UnicodeError: undefined encoding
    >>> "国将不国".decode("undefined")
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "C:\Python26\lib\encodings\undefined.py", line 22, in decode
        raise UnicodeError("undefined encoding")
    UnicodeError: undefined encoding
    
  • utf_8_sigutf-8编码差不多。只是在编码的加入BOM,解码的时候会忽略BOM。BOM(Byte Order Mark)用于标识字节序。讨论字节序太无聊了,详情可以参阅:

    http://en.wikipedia.org/wiki/Byte-order_mark

  • 最后,rot_13是可算是最大名鼎鼎的加密算法了,以其超弱的加密程度著称。它的加密规则是:

    A B C D E F G H I J K L M
    N O P Q R S T U V W X Y Z
    

    上下两行字母两两相互替换,A替换成NB替换成ON替换成AO替换成B,依此类推。。。。空格、标点符号都不变,碰到非ASCII码可能会报错。

    从字母表上看来就是字母往后挪了13位,所以叫"rotate by 13 places"。据说,这种加密方法是凯撒发明的。之所以是13位是因为:

    >>> "fish/panda/kaola".encode("rot-13")
    'svfu/cnaqn/xnbyn'
    >>> "fish/panda/kaola".encode("rot-13").encode("rot-13")
    'fish/panda/kaola'
    

    注意我们并没有用到decode()。因为rot13+rot13=rot26rot26就是啥都不变。

标题无“转载”即原创文章,版权所有。转载请注明来源:http://hgoldfish.com/blogs/article/56/。


暂时还没有任何评论。


何不来发表一下您对本文的看法(使用Markdown语法,分段空两行):