黑马程序员技术交流社区

标题: 【上海校区】python字符集-编解码一纸禅unicode,utf-8,ascii [打印本页]

作者: 不二晨    时间: 2019-2-19 10:22
标题: 【上海校区】python字符集-编解码一纸禅unicode,utf-8,ascii
概念

字节

字节(Byte)是计算机中数据存储的基本单元,一字节等于一个8位的比特,计算机中的所有数据,不论是保存在磁盘文件上的还是网络上传输的数据(文字、图片、视频、音频文件)都是由字节组成的。

字符

你正在阅读的这篇文章就是由很多个字符(Character)构成的,字符一个信息单位,它是各种文字和符号的统称,比如一个英文字母是一个字符,一个汉字是一个字符,一个标点符号也是一个字符。

字符集

字符集(Character Set)就是某个范围内字符的集合,不同的字符集规定了字符的个数,比如 ASCII 字符集总共有128个字符,包含了英文字母、阿拉伯数字、标点符号和控制符。而 GB2312 字符集定义了7445个字符,包含了绝大部分汉字字符。

对于一个字符集来说要正确编码转码一个字符需要三个关键元素:

字库表(character repertoire)、编码字符集(coded character set)、字符编码(character encoding form)。其中字库表是一个相当于所有可读或者可显示字符的数据库,字库表决定了整个字符集能够展现表示的所有字符的范围。编码字符集,即用一个编码值code point来表示一个字符在字库中的位置。字符编码,将编码字符集和实际存储数值之间的转换关系。

字符码

字符码(Code Point)指的是字符集中每个字符的数字编号,例如 ASCII 字符集用 0-127 连续的128个数字分别表示128个字符,例如 "A" 的字符码编号就是65。

字符编码

字符编码(Character Encoding)是将字符集中的字符码映射为字节流的一种具体实现方案,映射的目的是为了便于存储或在网络上传输。常见的字符编码有 ASCII 编码、UTF-8 编码、GBK 编码等。某种意义上来说,字符集与字符编码有种对应关系,例如 ASCII 字符集对应 有 ASCII 编码。ASCII 字符编码规定使用单字节中低位的7个比特去编码所有的字符。例如"A" 的编号是65,用单字节表示就是0×41,因此写入存储设备的时候就是b'01000001'。

编码、解码

编码的过程是将字符转换成字节流,解码的过程是将字节流解析为字符。



Unicode与UTF-8,ASCII,GBK等的关系

看完上面两个概念解释,那么解释UTF-8和Unicode的关系就比较简单了。Unicode就是上文中提到的字符码,而UTF-8就是字符编码,用于存储或在网络上传输,即Unicode字符码的一种实现形式。为了解决Unicode占用硬盘和流量大的问题产生的相关编码方式。随着互联网的发展,对同一字库集的要求越来越迫切,Unicode标准也就自然而然的出现。它几乎涵盖了各个国家语言可能出现的符号和文字,并将为他们编号。Unicode的编号从0000开始一直到10FFFF共分为16个Plane,每个Plane中有65536个字符。而UTF-8则只实现了第一个Plane,可见UTF-8虽然是一个当今接受度最广的字符集编码,但是它并没有涵盖整个Unicode的字库,这也造成了它在某些场景下对于特殊字符的处理困难。



UCS[Universial Character Set]和ISO 10646标准

ISO 10646标准定义了通用字符集UCS[Universal Character Set],是其他所有字符集合的超集。它保证了和其他字符集合之间可以来回转换,不会丢失信息。

UCS不仅给每个字符做了编码,而且还定义了一个官方的名称。用来表示一个UCS或者Unicode的十六进制数字通常是用"U+"来作为前缀的,例如用"U+0041"来表示拉丁文中的大写字母A。



UCS和Unicode的关系

简单粗暴的总结一下,就是两拨人搞的同一套标准。具体经过如下:

在1980年代后期,有独立的两拨人想创建一个通用的字符集合。一个是国际化标准组织ISO[Internaltional Organization for Standardization],另外一个是最初成员大部分是美国多语言软件服务提供商的财团发起的Unicode项目。幸运的是在1991年左右,两个项目的成员都意识到世界不需要两个统一的字符集。于是他们一起合作制定了一个字符表。虽然两个项目至今仍然存在并独立发布各自的标准,但是Unicode财团和国际化标准组织都已经同意会让Unicode和ISO10646标准互相兼容并会在未来紧密协作。

文件读写过程

在计算机内存中,统一使用Unicode的字符码,当需要保存到硬盘或者需要传输的时候,就转换为UTF-8等字符编码。

用记事本编辑的时候,从文件读取的UTF-8字符被转换为Unicode字符到内存里,编辑完成后,保存的时候再把Unicode转换为UTF-8保存到文件:





浏览网页的时候,服务器会把动态生成的Unicode内容转换为UTF-8再传输到浏览器:





所以会看到很多网页的源码上会有类似<meta charset="UTF-8" />的信息,表示该网页正是用的UTF-8编码。



为什么会出现乱码

简单的说乱码的出现是因为:编码和解码时用了不同或者不兼容的字符集。对应到真实生活中,就好比是一个英国人为了表示祝福在纸上写了bless(编码过程)。而一个法国人拿到了这张纸,由于在法语中bless表示受伤的意思,所以认为他想表达的是受伤(解码过程)。这个就是一个现实生活中的乱码情况。在计算机科学中一样,一个用UTF-8编码后的字符,用GBK去解码。由于两个字符集的字库表不一样,同一个汉字在两个字符表的位置也不同,最终就会出现乱码。



怎样判断当前python的编码方式?

以 --enable-unicode=ucs4 编译则:

>>> import sys

>>> print sys.maxunicode

1114111 //////////// 常用

以 --enable-unicode=ucs2 编译则:

>>> import sys

>>> print sys.maxunicode

65535



查询一个unicode字符的code point对应的十进制傎

ord(),可是是英文字母,也可以是汉字。

其对应的函数是chr()和unichr()



对字符串进行编码

使用字符串的encode()方法,

bytes字节码可以使用decode()方法进行解码



Little endian和Big endian

Unicode码可以采用UCS-2格式直接存储。以汉字”严“为例,Unicode码是4E25,需要用两个字节存储,一个字节是4E,另一个字节是25。存储的时候,4E在前,25在后,就是Big endian方式;25在前,4E在后,就是Little endian方式。

第一个字节在前,就是”大头方式“(Big endian),第二个字节在前就是”小头方式“(Little endian)。



UTF-8的编码规则

很简单,只有二条: 1)对于单字节的符号,字节的第一位设为0,后面7位为这个符号的unicode码。因此对于英语字母,UTF-8编码和ASCII码是相同的。 2)对于n字节的符号(n>1),第一个字节的前n位都设为1,第n+1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的unicode码。
---------------------
【转载,仅作分享,侵删】
作者:太阳山
原文:https://blog.csdn.net/salc3k/article/details/87212859
版权声明:本文为博主原创文章,转载请附上博文链接!


作者: 不二晨    时间: 2019-2-20 09:32
今天也要加油鸭
作者: 一个人一座城0.0    时间: 2019-2-21 09:14
看一看。




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2