Python字符串编码

ASCII码

我们知道,在总计机内部,全数的音信最后都表示为二个二进制的字符串。每三个二进制位(bit)有0和1二种情景,由此多少个二进制位就足以整合出256种意况,那被誉为3个字节(byte)。也正是说,二个字节一共能够用来代表256种区别的意况,每叁个景况对应三个标记,就是25九个标志,从0000000到11111111。
上个世纪60年间,美国制定了一套字符编码,对波兰语字符与二进制位之间的关系,做了合并显明。这被叫做ASCII码,向来沿用到现在。
ASCII码一共规定了1二十七个字符的编码,比如空格”SPACE”是32(二进制00一千00),大写的字母A是65(二进制0一千001)。那1贰十五个标志(包蕴3多少个无法打字与印刷出来的支配符号),只占用了三个字节的后面陆个人,最前头的一人统一规定为0。

非ASCII编码

立陶宛共和国(Republic of Lithuania)语用1二十六个标志编码就够了,可是用来代表其他语言,1贰14个记号是不够的。比如,在朝鲜语中,字母上方有注音符号,它就不可能用ASCII码表示。于是,一些欧洲国家就控制,利用字节中不了了之的参天位编入新的标志。比如,英语中的é的编码为130(二进制壹仟0010)。那样一来,那几个亚洲国家采用的编码连串,能够象征最多2伍1柒个记号。

可是,那里又出现了新的标题。分裂的国度有两样的字母,因而,哪怕它们都利用2六10个记号的编码方式,代表的假名却不一样。比如,130在葡萄牙语编码中代表了é,在丹麦语编码中却意味着了字母Gimel
(ג),在意大利语编码中又会表示另三个符号。可是无论怎么着,全部那么些编码格局中,0–127表示的符号是平等的,差异的只是128–255的这一段。

关于欧洲国家的文字,使用的记号就越多了,汉字就多达10万左右。二个字节只可以表示256种标志,肯定是不够的,就非得选取多个字节表明贰个标记。比如,简体粤语常见的编码形式是GB2312,使用四个字节表示多个汉字,所以理论上最多能够表示256×256=655叁二十一个标志。

普通话编码的难点须求专文探讨,这篇笔记不关乎。那里只提出,纵然都以用三个字节表示二个标志,然则GB类的汉字编码与后文的Unicode和UTF-8是毫无关系的。

Unicode

正如上一节所说,世界上存在着冒尖编码格局,同二个二进制数字能够被演讲成不相同的符号。由此,要想打开1个文本文件,就不可能不驾驭它的编码格局,不然用错误的编码形式解读,就会合世乱码。为啥电子邮件经常出现乱码?正是因为发信人和收信人使用的编码格局不同。

能够想像,假设有一种编码,将世界上拥有的号子都纳入其间。每一个标记都赋予3个旷世的编码,那么乱码难题就会消退。那就是Unicode,就像它的名字都意味着的,那是一种具有符号的编码。

海洋世界,Unicode当然是一个一点都不小的汇集,现在的局面得以容纳100多万个标志。每一个符号的编码都不相同,比如,U+0639意味着阿拉伯字母Ain,U+0041意味着拉脱维亚语的大写字母A,U+4E25代表汉字”严”。具体的符号对应表,能够查询unicode.org,也许特别的方块字对应表。

Unicode的问题

亟需专注的是,Unicode只是1个标记集,它只规定了符号的二进制代码,却从不明确这些二进制代码应该什么存款和储蓄。

譬如,汉字”严”的unicode是十六进制数4E25,转换到二进制数足足有1八人(100111000100101),也正是说这些符号的意味至少必要3个字节。表示其他更大的符号,大概需求三个字节或许6个字节,甚至越来越多。

那里就有多个严重的难点,第①个难题是,怎么样才能分别Unicode和ASCII?计算机怎么了然四个字节表示多少个标记,而不是个别代表七个标志呢?第③个难点是,大家早已理解,英文字母只用多少个字节表示就够了,假如Unicode统一鲜明,各个符号用五个或多个字节表示,那么每一种英文字母前都自然有二到多个字节是0,那对于仓库储存来说是大幅的浪费,文本文件的大大小小会就此大出二三倍,那是不能够接受的。

它们造成的结果是:1)出现了Unicode的种种存款和储蓄格局,也正是说有好二种差异的二进制格式,能够用来代表Unicode。2)Unicode在非常长一段时间内不也许松开,直到互连网的面世。

UTF-8

网络的推广,强烈须求出现一种统一的编码方式。UTF-8正是在网络上利用最广的一种Unicode的落到实处格局。别的完结方式还包涵UTF-16(字符用多少个字节或八个字节表示)和UTF-32(字符用五个字节表示),然而在互连网上基本不用。重复贰回,那里的涉嫌是,UTF-8是Unicode的落到实处格局之一。

UTF-8最大的1个特色,正是它是一种变长的编码格局。它可以行使1~5个字节表示三个标志,根据分裂的号子而变化字节长度。
UTF-8的编码规则非常的粗略,唯有二条:

1)对于单字节的标记,字节的首先位设为0,前边八个人为那个符号的unicode码。由此对于阿拉伯语字母,UTF-8编码和ASCII码是一致的。

2)对于n字节的记号(n>1),第一个字节的前n位都设为1,第n+1个人设为0,后边字节的前两位一律设为10。剩下的远非提及的二进制位,全体为这些符号的unicode码。
下表总括了编码规则,字母x表示可用编码的位。

Unicode符号范围 | UTF-8编码格局

(十六进制) | (二进制)

——————–+———————————————

0000 0000-0000 007F | 0xxxxxxx

0000 0080-0000 07FF | 110xxxxx 10xxxxxx

0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx

0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

跟据上表,解读UTF-8编码格外简单。要是2个字节的第一个人是0,则这些字节单独正是叁个字符;若是第②位是1,则延续有微微个1,就象征方今字符占用多少个字节。

上边,依然以汉字”严”为例,演示如何兑现UTF-8编码。

已知”严”的unicode是4E25(10011一千100101),依照上表,可以发现4E25地处第②行的界定内(0000
0800-0000 FFFF),由此”严”的UTF-8编码需求四个字节,即格式是”1110xxxx
10xxxxxx
10xxxxxx”。然后,从”严”的最后多少个二进制位开首,依次从后迈入填入格式中的x,多出的位补0。这样就取得了,”严”的UTF-8编码是”11100100
1011一千 10100101″,转换来十六进制正是E4B8A5。

python 中的字符串编码

在使用

#!/usr/bin/env python
# -*- coding:utf-8 -*-

默许的国语编码为utf8

>>> kel = '中' 
>>> kel
'\xe4\xb8\xad'

加入u以后,变成unicode

>>> kel = u'中'
>>> kel
u'\u4e2d'

python 文件字符串编码

保存Unicode字符到文本文书档案

#coding=utf-8
import os

def write_use_open(filepath):
    try:
        file = open(filepath, 'wb')
        try:
            content = '中华人民共和国abcd \r\nee ?!>??@@@!!!!!???¥@#%@%#xx学校ada\r\n'
            print file.encoding
            print file.newlines
            print file.mode
            print file.closed
            print content
            file.write(content)
        finally:
            file.close()
            print file.closed
    except IOError, e:
        print e


if __name__ == '__main__':
    filepath = os.path.join(os.getcwd(), 'file.txt')
    write_use_open(filepath)

发端笔者是IDLE编写的,并间接按F5运营,没觉察难题,文件也被科学地保存,文件的编码类型也是utf-8.

然则我用命令行运维,却发现展现出现乱码了,然后在开辟文件发现文件被科学保存了,编码照旧utf-8:

海洋世界 1

题材是命令行无法自动识别字符编码吧,因为IDLE展现是天经地义的,它扶助utf-8。

于是自个儿修改了代码,在字符串前加了’u’,表明content是unicode:
content = u’中国abcd \r\nee
?!>??@@@!!!!!???¥@#%@%#xx学校ada\r\n’

可是运转载现,命令行是正确呈现了,不过却出现极度:

海洋世界 2

很明白,content里含有了非ASCII码字符,肯定无法利用ASCII来进展编码的,write方法是私下认可使用ascii来编码保存的。

很简单就能够想到,在保存在此之前,先对unicode字符进行编码,小编选用utf-8

#coding=utf-8
import os

def write_use_open(filepath):
    try:
        file = open(filepath, 'wb')
        try:
            content = u'中华人民共和国abcd \r\nee ?!>??@@@!!!!!???¥@#%@%#xx学校ada\r\n'
            print file.encoding
            print file.newlines
            print file.mode
            print file.closed
            print content
            print unicode.encode(content, 'utf-8')
            file.write(unicode.encode(content, 'utf-8'))
        finally:
            file.close()
            print file.closed
    except IOError, e:
        print e

if __name__ == '__main__':
    filepath = os.path.join(os.getcwd(), 'file.txt')
    write_use_open(filepath)

看看运行结果:

海洋世界 3

OK了打开文书档案也是科学的。
读取文件又何以?同样道理,只是本次不是编码了,而解码:

def read_use_open(filepath):
    try:
        file = open(filepath, 'rb')
        try:
            content = file.read()
            content_decode = unicode(content, 'utf-8')
            print 'original text'
            print content
            print 'decode using utf-8'
            print content_decode
        finally:
            file.close()
    except IOError, e:
        print e

if __name__ == '__main__':
    filepath = os.path.join(os.getcwd(), 'file.txt')
    write_use_open(filepath)
    print 'read file ---------------------------'
    read_use_open(filepath)

海洋世界 4

缘何不直接在open的时候就解码呢?呵呵,能够啊,能够运用codecs的open方法

import codecs
def read_use_codecs_open(filepath):
    try:
        file = codecs.open(filepath, 'rb', 'utf-8')
        try:
            print 'using codecs.open'
            content = file.read()
            print content
        finally:
            file.close()
    except IOError, e:
        print e

海洋世界 5

互联网中乱码的化解

中文网页中,有个别网页抓取下来今后,由于网页编码的标题,供给开始展览解码。首先我们要求判定网页中到底使用的是什么样编码,在根据这么些编码把字符串变成utf8编码。

在探测编码时,chardet第1方库非常的福利。

网页编码判断:

import urllib
rawdata = urllib.urlopen('http://tech.163.com/special/00097UHL/tech_datalist.js').read()
import chardet
print chardet.detect(rawdata)

{'confidence': 0.99, 'language': 'Chinese', 'encoding': 'GB2312'}

经过 chardet
探测出,网页的字符编码为GB2312编码,通过unicode转化为utf8编码:

str_body = unicode(rawdata, "gb2312").encode("utf8")

越多入门教程能够参考:[http://www.bugingcode.com/python_start/]
(http://www.bugingcode.com/python_start/)