字符集=字库表(character repertoire)、编码字符集(coded character set)、字符编码(character encoding form
字库表=字库表是一个相当于所有可读或者可显示字符的数据库
编码字符集=用一个编码值code point来表示一个字符(即该字符在子库表中的位置)
字符编码=编码字符集和实际存储数值之间的转换关系
不直接把序号作为存储内容就好了,还要多此一举通过字符编码把序号转换成另外一种存储格式原因:节约精神
统一字库表的目的是为了能够涵盖世界上所有的字符,但实际使用过程中会发现真正用的上的字符相对整个字库表来说比例非常低。
库中字符太多,都用序号表示所有字符所占字节都要3B,占空间大;而我们只需库中的一部分字符,在UTF-8编码中原本只需要一个字节的ASCII字
符,仍然只占一个字节。而像中文及日语这样的复杂字符就需要2个到3个字节来存储。
ASCII
ASCII和UTF-8(兼容ASCI)
| 字符 | ASCII | Unicode | UTF-8 |
|---|---|---|---|
| A | 01000001 | 00000000 01000001 | 01000001 |
| 中 | x | 01001110 00101101 | 11100100 10111000 10101101 |
ASCII编码实际上可以被看成是UTF-8编码的一部分,所以,大量只支持ASCII编码的历史遗留软件可以在UTF-8编码下继续工作。
UTF-8和Unicode的关系
Unicode=编码字符集,而UTF-8=字符编码,即Unicode规则字库的一种实现形式;
用一个字节表示英文字符,用3个字节表示汉字,
UTF-8:
BMP:
| Byte 1 | Byte 2 | Byte3 |
|---|---|---|
| 0xxx xxxx | ||
| 110x xxxx | 10xx xxxx | |
| 1110 xxxx | 10xx xxxx | 10xx xxxx |
总:
000000 - 00007F ║ 0xxxxxxx
000080 - 0007FF ║ 110xxxxx 10xxxxxx
000800 - 00FFFF ║ 1110xxxx 10xxxxxx 10xxxxxx
010000 - 10FFFF ║ 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx //4字节模板有21个x,即可以容纳21位二进制数字。Unicode的最大码位0x10FFFF也只有21位。
我们分别看三个从一个字节到三个字节的UTF-8编码例子:
| 实际字符 | 在Unicode字库序号的十六进制 | 在Unicode字库序号的二进制 | UTF-8编码后序号的二进制 | UTF-8编码后的十六进制 |
| $ | 0024 | 010 0100 | 0010 0100 | 24 |
| ¢ | 00A2 | 000 1010 0010 | 1100 0010 1010 0010 | C2 A2 |
| € | 20AC | 0010 0000 1010 1100 | 1110 0010 1000 0010 1010 1100 | E2 82 AC |
细心的读者不难从以上的简单介绍中得出以下规律:
3个字节的UTF-8十六进制编码一定是以E开头的
2个字节的UTF-8十六进制编码一定是以C或D开头的
1个字节的UTF-8十六进制编码一定是以比8小的数字开头的
乱码
编码和解码时用了不同或者不兼容的字符集:一个用UTF-8编码后的字符,用GBK去解码。由于两个字符集的字库表不一样,同一个 汉字在两个字符表的位置也不同,最终就会出现乱码。
计算机系统通用的字符编码工作方式:
在计算机内存中,统一使用Unicode编码,当需要保存到硬盘或者需要传输的时候,就转换为UTF-8编码。
用记事本编辑的时候,从文件读取的UTF-8字符被转换为Unicode字符到内存里,编辑完成后,保存的时候再把Unicode转换为UTF-8保存到文件:
浏览网页的时候,服务器会把动态生成的Unicode内容转换为UTF-8再传输到浏览器:
所以你看到很多网页的源码上会有类似<meta charset="UTF-8" />的信息,表示该网页正是用的UTF-8编码。
GB2312 (双字节编码,区位码) 兼容ASCI
区从1(十进制)开始,一直到94(十进制),每区含有94个位,位从1(十进制)开始,一直到94(十进制),共8836(94 * 94)个码位。
0101 - 9494

例如:'李'字的区位码为3278(表示在32区,78位)。1. 将32(区)转化为十六进制为20。2. 加上A0为C0。3. 将78(位)转化为十六进制为4E。4. 加上A0为EE。5. 组合区和位,为C0EE。6. 得到GB2312编码,即'李'字的GB2312编码为C0EE。
BIG5(双字节编码)
繁体中文字符集编码标准
GBK(双字节编码)加入对繁体字的支持,兼容ASCIGB2313
完全兼容GB2312编码,不兼容BIG5编码。即如果使用GB2312编码,使用GBK解码是完全正常的。相比于GB2312编码,GBK编码了更多汉字。
Unicode表包含了1114112个码点,即从000000(十六进制) - 10FFFF(十六进制)。Unicode将码空间划分为17个平面,从00 - 10(十六进制,最高两位),即从0 - 16(十进制),每个平面有65536个码点(2^16),其中最重要的是第一个Unicode平面(码位从0000 - FFFF),包含了最常用的字符,该平面被称为基本多语言平面(Basic Multilingual Plane),缩写为BMP,其他平面称为辅助平面(Supplementary Planes),在基本多文种平面內, 从D800到DFFF之间的码位区段是永久保留不映射到字符的, 因此UTF-16编码巧妙的利用了这保留下来的码位来对辅助平面内的字符进行编码
Windows 记事本
· 所谓的「ANSI」指的是对应当前系统 locale 的遗留(legacy)编码。[1]
· 所谓的「Unicode」指的是带有 BOM 的小端序 UTF-16。[2]
· 所谓的「UTF-8」指的是带 BOM 的 UTF-8。[3]
[1] Windows 里说的「ANSI」其实是 Windows code pages,这个模式根据当前 locale 选定具体的编码,比如简中 locale 下是 GBK。把自己这些 code page 称作「ANSI」是 Windows 的臭毛病。在 ASCII 范围内它们应该是和 ASCII 一致的。
[2] 把带有 BOM 的小端序 UTF-16 称作「Unicode」也是 Windows 的臭毛病。Windows 从 Windows 2000 开始就已经支持 surrogate pair 了,所以已经是 UTF-16 了,「UCS-2」这个说法已经不合适了。UCS-2 只能编码 BMP 范围内的字符,从 1996 年起就在 Unicode/ISO 标准中被 UTF-16 取代了(UTF-16 通过蛋疼的 surrogate pair 来编码超出 BMP 的字符)。都十多年了,求求大家别再误称了……
[3] 把带 BOM 的 UTF-8 称作「UTF-8」又是 Windows 的臭毛病。如果忽略 BOM,那么在 ASCII 范围内与 ASCII 一致。另请参见:「带 BOM 的 UTF-8」和「无 BOM 的 UTF-8」有什么区别?zhihu.com/question/2016
附加说明:
Windows早期(至少是95年以前的事情了)是ANSI字符集的,也就是说一个中文文本,在Windows简体中文版显示的是中文,到Windows日文版显示的就不知道是什么东西了。对于 ASCII、GB 2312、Big5、GBK、GB 18030 之类的遗留方案来说,基本上一个字符集方案只使用一种编码方案。
比如 ASCII 这部标准本身就直接规定了字符和字符编码的方式,所以既是字符集又是编码方案;而 GB 2312 只是一个区位码形式的字符集标准,不过实际上基本都用 EUC-CN 来编码,所以提及「GB 2312」时也说的是一个字符集和编码连锁的方案;GBK 和 GB 18030 等向后兼容于 GB 2312 的方案也类似。
于是,很多人受这些遗留方案的影响而无法理解字符集和编码的关系。
对于 Unicode,字符集和编码是明确区分的。Unicode/UCS 标准首先是个统一的字符集标准。而 Unicode/UCS 标准同时也定义了几种可选的编码方案,在标准文档中称作「encoding form」,主要包括 UTF-8、UTF-16 和 UTF-32。
所以,对 Unicode 方案来说,同样的基于 Unicode 字符集的文本可以用多种编码来存储、传输。
所以,用「Unicode」来称呼一个编码方案不合适,并且误导
后来,Windows支持了Unicode,但当时大部分软件都是用ANSI编码的,unicode还不流行,怎么办?Windows想了个办法,就是允许一个默认语言编码,就是当遇到一个字符串,不是unicode的时候,就用默认语言编码解释。(在区域和语言选项里可以改默认语言)
这个默认语言,在不同Windows语言版本里是不同的,在简体中文版里,是GBK,在繁体中文版里,是BIG5,在日文版里是JIS
而记事本的ANSI编码,就是这种默认编码,所以,一个中文文本,用ANSI编码保存,在中文版里编码是GBK模式保存的时候,到繁体中文版里,用BIG5读取,就全乱套了。
记事本也不甘心这样,所以它要支持Unicode,但是有一个问题,一段二进制编码,如何确定它是GBK还是BIG5还是UTF-16/UTF-8?记事本的做法是在TXT文件的最前面保存一个标签,如果记事本打开一个TXT,发现这个标签,就说明是unicode。标签叫BOM,如果是0xFF 0xFE,是UTF16LE,如果是0xFE 0xFF则UTF16BE,如果是0xEF 0xBB 0xBF,则是UTF-8。如果没有这三个东西,那么就是ANSI,使用操作系统的默认语言编码来解释。
Unicode的好处就是,不论你的TXT放到什么语言版本的Windows上,都能正常显示。而ANSI编码则不能。(UTF-8的好处是在网络环境下,比较节约流量,毕竟网络里英文的数据还是最多的)
举例:
同样一段中文文本(可以插入一些英文),保存成ANSI/Unicode/UTF-8,三个文件。
修改windows的默认语言为日语之类的(WIN7的改法是:控制面板-时钟、语言和区域-更改显示语言-区域和语言-管理-非unicode程序语言-更改区域设置/WNIXP改法是:控制面板-区域和语言选项-非unicode程序语言)。
修改完要求重启,重启以后,再打开这三个文件,ANSI的编码全乱了,其余两个都正常显示,这就是UNICODE的作用。
另外,为什么记事本、开始菜单什么的还是正确的中文呢?明明我已经改了默认语言了?因为它们的程序编码也是unicode的。
要把txt发给国外的朋友或者用在非中文的操作系统/软件里,那么你的编码最好选择unicode
reference:
https://www.liaoxuefeng.com/wiki/001374738125095c955c1e6d8bb493182103fac9270762a000/001386819196283586a37629844456ca7e5a7faa9b94ee8000 Python对Unicode的支持。
http://www.cnblogs.com/leesf456/p/5317574.html各种编码
http://os.51cto.com/art/201503/467929.htm字符集和字符编码
http://www.freebuf.com/articles/others-articles/25623.html Unicode的流言终结者和编码大揭秘:Unicode不是编码,只是代表一个字符的编号

3107

被折叠的 条评论
为什么被折叠?



