文章启发来源:
字符编码方式
note from wiki:
从维基百科上得到的一些理解,一个字符的unicode编码是确定的,但是在传输过程中,由于不同系统平台的设计不一致,所以对unicode编码的实现方式是有所不同的。unicode的实现方式成为unicode转换格式(简称UTF)例如对于一个包含基本7位ASCII字符的unicode文件,如果都使用2字节的原unicode编码传输,会造成浪费。对于这种情况可以使用UTF-8编码,它是一种变长编码,对于基本ASCII字符仍然采用7位编码表示,占用一个字节。
意思其实就是,unicode规定了符号的二进制代码的符号集,但是并没有规定二进制代码应该如何存储。也就是说,在计算机的存储中,一个字符的存放方式并不一定会与它的unicode编码一致。这是因为采用了不同的编码方式所导致的。
自己整理的一些背景:
编码一开始是使用ASCII码来进行编码的,但是这个编码方式是针对英文为基础的国家的。后来,各个地区因为各自的需要,开始使用127位以后的扩展位。比如中国,因为几万个汉字,所以单靠单个127位是根本不够的,所以就规定,使用高于127位的两个字节来表示汉字。当然也就顺便把原来的一些其他扩展西方字符给出重新编码了。即,全角字符(半角字符可类推)GB2312。
后来标准随着发展,GBK变成了GB18030,即,只要第一个字节表示的十六进制数大于127,就表示汉字的开始。(DBCS,双字节字符。台湾地区的BIG5)。
后来unicode开始制定了,它的制定标准在上面的引用中可以看到,使用的是两个字节来表示字符。因此在unicode标准里,无论是汉字的全角字符还是英语的半角字符,都是一个字符,两个字节。但是unicode如何在网络上传播也是一个问题。于是,便有了UTF。UTF与unicode的转换关系如下:
note:
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
其中的x是要用左边的十六进制码转化为二进制码后,代替相关的位。UTF-8的编码规则很简单,只有二条:
1)对于单字节的符号,字节的第一位设为0,后面7位为这个符号的unicode码。因此对于英语字母,UTF-8编码和ASCII码是相同的。
2)对于n字节的符号(n>1),第一个字节的前n位都设为1,第n+1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的unicode码。
在查阅了几篇blog后,举个例子:比如说你现在的file用的是编辑器等(比如说是windows上的记事本,且设置它为ASCII
,unicode
(其实是带BOM的utf-8))默认的编码方式,那么存储的时候用的就是这种编码方式对应的在硬盘中的存储方式。比如说,此刻我用sublime 3
打开,而且我的sublime 3
中只有utf系列和一些西文字体的编码方式,那么如果打开的文件用的是ASCII
保存的文件,则此时会显示的乱码;而如果使用的是unicode
的编码方式,也是能打开的,而且不会出现乱码的情况。
在终端或者编辑器中,如果没有进行特殊声明的话,就会使用它们默认的编码格式进行编码,或者是GBK
或者是UTF
,如果是ascii
的话,汉字字符是无法存储的,因为没有配套的编码。所以一般能显示汉字的地方,使用的是GBK
等等编码格式,要转码的话,先转换为unicode
,然后再转换为其他东西。
关于python的encoding
参考知乎上的一个回答传送门
以我自己的理解就是:
首先得分清楚编码问题,在不同的环境中,编码是不同的。在终端的情况下,(windows 中是cmd,ubuntu 下的terminal,远程登录是xshell),所以他们的编码是不同的。shell环境下,windows的编码是GBK,ubuntu一般是utf-8。-------在文本编辑的情况下,与上面的情况类似,是根据编辑器的情况决定的.
在python中的情况是,unicode(A,B)的意思是用B的编码方案将A解码,并将结果返回为unicode字符串。所以一般在出现UnicodeDecodeError时候,错误的来源应该就是:
文件保存时的编码方式是编辑器默认的保存方式,而在运行环境中默认的编码方式与该文件方式并不相同,很有可能是有非ANIS的字符出现所致。因为环境无法编码该文件。
在文件保存的时候,带有BOM 。BOM(byte order mark)是为 UTF-16 和 UTF-32 准备的,用于标记字节序(byte order)。微软在 UTF-8 中使用 BOM 是因为这样可以把 UTF-8 和 ASCII 等编码明确区分开,但这样的文件在 Windows 之外的操作系统里会带来问题。
所以啊,最后在文件的头里面需要加入utf-8的说明,最好不要用BOM。
一点有意思的扩展,在pythonIDE中
两种终端下的显示
# 环境是sublime 3
1 >>> u"知乎".encode('utf-8')
2 '\xe7\x9f\xa5\xe4\xb9\x8e'
3 >>> u"知乎".encode('gb2312')
4 '\xd6\xaa\xba\xf5'
5 >>> '知乎'.encode('utf-8')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe7 in position 0: ordinal not in range(128)
7 >>> '知乎'
'\xe7\x9f\xa5\xe4\xb9\x8e'
8 >>> u'知乎'
u'\u77e5\u4e4e'
9 >>> u'知乎'.encode('utf-8').decode('utf-8')
u'\u77e5\u4e4e'
# 环境是windows:
>>>'知乎'
'\xd6\xaa\xba\xf5'
>>>u'知乎'
u'\u77e5\u4e4e'
>>> u"知乎".encode('utf-8')
'\xe7\x9f\xa5\xe4\xb9\x8e'
>>> u"知乎".encode('gb2312')
'\xd6\xaa\xba\xf5'
#还是补充一下举这个例子的本意:
#从第七行(数字标出的,以下也是一样)以及第一二行中可以看出,两个输出结果是相同的,第一行说明 将 u'知乎' unicode字符串按照utf-8的编码方式进行编码,并以字节串的形式输出来。
#但是如果换成的是 u'知乎' 的话,则表示的是将这个汉字用unicode编码的形式存放。(猜测是自动调用了encode方法)。所以呢,第九行意思是将utf-8编码的字符串用utf-8解码出来。
#下面又在windows上补充了下,可以看出在不同的终端下,使用的编码方式可能是不同的,比如在windows上就有可能是,当输入汉字的时候,终端用gbk的编码方式将汉字编码。
最后再贴一个链接参考blog
总结
在这两天的调试过程中,开始将unicode的相关知识模块化,所以在此也特地写下这些东西,作为一个总结。在写代码的时候,如果一个文件中有超过ascii的字符的话,那么需要在py文件的第一行加以声明。这是因为不同的环境,不同的编译器所默认的编码字符的格式是不同的。最好能够统一以unicode字符串为基础进行转换。
update
这是一个在segmentfault网站上回答过的一个东西的链接。链接1
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。