细说ASCII、GB212/GBK/GB1800、Unicode、UTF
细说ASCII、GB212/GBK/GB1800、Unicode、UTF
参考:
《编码标准-GB212 GBK GB1800》
《字符编码笔记:ASCII,Unicode 和 UTF-8》
《字体编辑用中日韩汉字Unicode编码表》
《程序员趣味读物:谈谈Unicode编码》
1. 最简单的ASCII码。
ASCII码使用1个字节记录了128个常用的字符(ASCII规定第一个bit位固定为0,2^7=128),包含控制字符(如:键盘的空格、Tab键),以及打印字符(如:数字、英文字母等)。
看下面的表格:
2. 汉字编码,从GB212说起
1980年,为了使每个汉字有一个全国统一的代码,我国颁布了汉字编码的国家标准:GB212-80《信息交换用汉字编码字符集》基本集,这个字符集是我国中文信息处理技术的发展基础,也是国内所有汉字系统的统一标准。
在这个标准中,我们规定使用两个字节表示一个字符,又为了兼容ASCII码,规定每个字节的首bit位固定为1。这样最终编码后的范围是:0xA1A1 - 0xFEFE
(共94*94=886个码位
),其中收录了汉字676个(其中一级汉字755,二级汉字008个),覆盖率达到了99.75% 。
其实,在GB212中还有区位表的概念:
将所有的字符都分为94区,每区又有94位,
- 01-09 区为特殊符号
- 10-15 区为用户自定义符号区(未编码)
- 16-55 区为一级汉字,按拼音排序
- 56-87 区为二级汉字,按部首/笔画排序
- 88-94 区为用户自定义汉字区(未编码)
.
示例如下:
可以通过这里查看完整的区位码列表:《区位码全表》
实际计算机存储的时候肯定不是按照区位码存的(还要避开ASCII的字符嘛),所以GB212的存储规则如下:
注意:上面的“a”不是ASCII中的a,而是GB212中的“a”。
另外,我们知道ASCII码的a其实就是0x61(即:97,01000001)。
基于以上三个字符的分析,我们新建一个文本文件并输入:“aa啊”,并另存为“ASI”编码(其实就是GBK编码,GBK兼容GB212,这里就把GBK当做GB212),如下:
保存后,我们换个软件打开,观察下16进制,这里我使用editplus,如下:
这里实验的结果和我们分析的结果正好一致。
0x61:表示ASCII中的a
0xAE1:表示GB212中的a
0xB0A1:表示汉字“a”
.
注意:
现在已经不用区位码表示了,也不用再考虑区位码到二进制存储的转换了。后面的GBK编码就是直接在GB212的二进制存储上做的扩展。
. 全角和半角?
对于英文字母和部分标点符号有全角和半角的区别,这是因为这些字母和符号在ASCII中已经定义了一遍,但GB212中又把这些字母和符号重新定义了一遍(应该是因为中文排版显示不同吧),所以为了区分字母和标点符号究竟是指ASCII中的还是GB212中的,出现了全角和半角的说法。
- 半角:指ASCII中的字符;
- 全角:指GB212中的字符;
而对于汉字来说,是没有全角和半角的区别的,因为ASCII中本就没有汉字。
4. GBK编码
GBK全称《汉字内码扩展规范》(GBK即“国标”、“扩展”汉语拼音的第一个字母,英文名称:Chinese Internal Code Specification) ,中华人民共和国全国信息技术标准化技术委员会1995年12月1日制订。
指定它的原因?
虽然GB212中已覆盖了99.75% 的汉字,但仍然有不少生僻字不在规范里面,作为计算机标准不能漏掉这些。
编码特点:
- GBK编码,是在GB212-80标准基础上的内码扩展规范,使用了双字节编码方案,其编码范围从8140至FEFE(剔除xx7F),共2940个码位,共收录了2100个汉字,完全兼容GB212-80标准,支持国际标准ISO/IEC10646-1和国家标准GB1000-1中的全部中日韩(CJK)汉字,并包含了BIG5编码中的所有汉字;
- GBK编码方案于1995年10月制定, 1995年12月正式发布,中文版的WI95、WI98、WIDOWS T以及WIDOWS 2000、WIDOWS XP、WI 7等都支持GBK编码方案;
GBK对应的区位码?
从上面GBK的描述中,没有发现区位码的信息,没错,GBK是《汉字内码扩展规范》,也就是说GBK不再使用区位码,而是直接对GB212的转储二进制进行的扩展。
GBK是如何扩展的GB212,为什么GB212最多存储886个码位,而GBK可以存储2940个?
GBK在扩展GB212的时候,移除了第二个字节首bit位必须为1的限制,且又做了其他扩展,所以GBK的编码范围是:0x8140 - 0xFEFE,最多能表示的码位:
(0xFE-0x811)*(0xFE-0x401) => 126*191=24066
然后,GBK又规定去除0x xx7F 一条线,所以GBK最终表示126*190=2940
个码位,共收入 21886 个汉字和图形符号,其中汉字(包括部首和构件)2100 个,图形符号 88 个。
5. GB1800编码
随着计算机的普及,我国后来又在GBK上扩展字符,这被称为GB1800,如:GB1800-2000(2000年发布),GB1800-2005(2005年发布),同时兼容ASCII、GB212、GBK、基本兼容Unicode,特点如下:
- 采用变长多字节编码,每个字可以由1个、2个或4个字节组成。;
- 编码空间庞大,最多可定义161万个字符;
- 基本完全支持Unicode,无需动用造字区即可支持中国国内少数民族文字、中日韩和繁体汉字以及emoji等字符;
另外,GB1800在微软视窗系统中的代码页为5496。
6. Big5
已被GBK包含。
Big5,又称为大五码或五大码,是使用繁体中文(正体中文)社区中最常用的电脑汉字字符集标准,共收录1,060个汉字。
7. 大端存储和小端存储
参考:《大小端(数据在内存中的存储)》
如果有一个编码单元需要用大于1个字节表示,那么要说明这个编码单元放在这几个字节内的顺序是怎样的。
比如说,int类型占用四个字节,那么这四个字节就是一个编码单元,内存中这四个字节排列如下:
小端存储如下(int i=0x00000001; //数字1):
大端存储如下(int i=0x00000001; //数字1):
如果我们在调试中观察内存(使用c)就能观察到效果了:
如果想使用c#看,需要使用unsafe模式,先设置工程属性:
然后代码如下:
8. Unicode
Unicode是国际组织制定的可以容纳世界上所有文字和符号的字符编码方案。Unicode用数字0-0x10FFFF来映射这些字符,最多可以容纳1114112个字符,或者说有1114112个码位(17*256*256=1114112)
。码位就是可以分配给字符的数字。
Unicode的学名是Universal Multiple-Octet Coded Character Set,简称为UCS。UCS可以看作是Unicode Character Set的缩写。
前面提到从ASCII、GB212、GBK到GB1800的编码方法是向下兼容的。而Unicode只与ASCII兼容,与GB码不兼容。
例如“汉”字的Unicode编码是6C49,而GB码是BABA。
Unicode 在1990年开始研发,1994年正式公布。
2005年月1日推出的Unicode 4.1.0。
2020年月10日推出的Unicode 1.0.0。
Unicode 1.0.0的官方文档:
.0.0/UnicodeStandard-1.0.pdf
Unicode的编码范围:
完整的范围,请参考:《百度百科:统一码》
0000-007F:C0控制符及基本拉丁文 (C0 Control and Basic Latin)
:也即ASCII码
0080-00FF:C1控制符及拉丁文补充-1 (C1 Control and Latin 1 Supplement)
0100-017F:拉丁文扩展-A (Latin Extended-A)
0180-024F:拉丁文扩展-B (Latin Extended-B)
0250-02AF:国际音标扩展 (IPA Extensi)
02B0-02FF:空白修饰字母 (Spacing Modifiers)
…此处省略
4E00-9FFF:CJK 统一表意符号 (CJK Unified Ideographs)
:中文汉字大多在这个区
…此处省略
10000–1FFFF: 第1辅助平面,多文种补充平面(Supplementary Multilingual Plane, SMP) [2]
20000–2FFFF: 第2辅助平面,表意文字补充平面(Supplementary Ideographic Plane, SIP) [2]
0000–FFFF: 第辅助平面,表意文字第三平面(Tertiary Ideographic Plane, TIP)
40000–DFFFF:第4-1辅助平面,尚未使用
E0000–EFFFF: 第14辅助平面,特别用途补充平面(Supplementary Special-purpose Plane, SSP)
F0000–FFFFF:第15辅助平面,保留作为私人使用区(Private Use Area, PUA)
100000–10FFFF:第16辅助平面,保留作为私人使用区(Private Use Area, PUA)
9. Unicode中的Emoji表情
由于Emoji符号是互联网文化的产物,所以它在Unicode表的后面部分,以下是部分Emoji表情在Unicode表中的排列:
完整的列表,参见Unicode官方文档:《Full Emoji List, v1.1》
10. UCS-2和UTF-16、UCS-4和UTF-2、UTF-8
上节说到Unicode统一了世界字符的编码标准,但是没有提到这些字符应该怎样转储到计算机中。
Unicode中包含1个字节(如:ASCII码)、两个字节(如:中文)和三个字节(如:第一辅助平面)的长度,为了将Unicode存储到计算机中出现了UCS-2
、UCS-4
、UTF-16
、UTF-2
、UTF-8
几种算法。其中UTF-8
已成事实上的流行者。
-
UCS-2 和 UTF-16编码方式
UCS-2 的编码固定占用2个字节,它包含6556个编码空间。但固定的两个字节不足以覆盖所有的Unicode字符,于是UTF-16诞生了,与UCS-2一样,它使用两个字节为全世界最常用的6K字符编码,不同的是,它使用4个字节对不常用的字符进行编码。UTF-16属于变长编码。
-
UCS-4 和 UTF-2编码方式
UCS-4的编码固定占用4个字节,编码空间为0x00000000 - 0x7FFFFFFF(可以编码20多亿个字符)。但实际使用范围并不超过0x10FFFF,并且为了兼容Unicode标准,ISO也承诺将不会为超出0x10FFFF的UCS-4编码赋值。由此UTF-2编码被提出来了,它的编码值与UCS-4相同,只不过其编码空间被限定在了0~0x10FFFF之间。因此也可以说:UTF-2是UCS-4的一个子集。
-
UTF-8
也是使用变长字节表示(1-4个字节表示)。
根据 Unicode 编号的大小,编号小的使用的字节就少,编号大的使用的字节就多。使用的字节个数从 1 到 4 个不等。
UTF-8 的编码规则是:- ① 对于单字节的符号,字节的第一位设为 0,后面的7位为这个符号的 Unicode 码,。
- ② 对于n字节的符号 (n>1),第一个字节的前 n 位都设为 1,第 n1 位设为 0,后面字节的前两位一律设为 10,剩下的没有提及的二进制位,全部为这个符号的 Unicode 码 。
UTF-8编码实例:
严的 Unicode 是4E25(100111000100101),根据上表,可以发现4E25处在第三行的范围内(0000 0800 - 0000 FFFF),因此严的 UTF-8 编码需要三个字节,即格式是1110xxxx 10xxxxxx 10xxxxxx。然后,从严的最后一个二进制位开始,依次从后向前填入格式中的x,多出的位补0。这样就得到了,严的 UTF-8 编码是11100100 10111000 10100101,转换成十六进制就是E4B8A5。
11. UTF-16 LE、UTF-16 BE、UTF-2 LE和UTF-2 BE
我们在记事本另存为的时候还能看到UTF-16 LE 和 UTF-16 BE的选项,这是因为在制定UTF-16编码的时候允许自己指定字节的存放顺序,这和上面说的大小端存储是一个意思。
UTF-2的和UTF-16一样也有这个特点。
而GBK和UTF-8均没有大小端存储的区别,因为它们都是按照字节的顺序从低位开始排列的。
以汉字 “严” 为例,它的Unicode编码为4E25,我们打开记事本,写入汉字 “严” ,并另存为 UTF-16 LE:
然后,我们使用editplus打开,观察它的16进制如下:
如果,我们另存为UTF-16 BE,那么16进制显示如下:
12. UTF-8和UTF-8-BOM
虽然UTF-8没有大小端存储的区别,但是我们会看到UTF-8-BOM类型的编码,那么有BOM和无BOM的啥区别呢?
带BOM的会在文本的前面添加EF BB BF
三个字节以表示这是UTF-8编码。
还是以汉字“严”为例,我们知道“严”的UTF-8编码为:0xE4B8A5,下面我们打开记事本,输入汉字“严”,将它保存为UTF-8编码:
然后,用editplus打开观察16进制,如下:
如果,我们将它保存为带BOM的UTF-8,然后观察16进制,会发现在首部多了个字节,如下:
虽然,带BOM的UTF-8编码能更好的表示文本文件,但带bom的shell脚本在linux执行的时候却会报错,所以除非必须,不要使用带BOM的UTF-8编码。
1. 如何根据文本首字节确定其编码方式
首先,由于GBK不存在字节序,文本前端不需要加字节说明,不带BOM的UTF-8编码文本也不需要加字节说明,所以下面的判断只能是识别已经指明编码格式的文本。
14. 编码总结(字符集和字符编码)
区分字符集和字符编码的概念:
- 字符集:定义了一套字符,比如:GB212、GBK等定义了一整套的中文符号,Unicode定义了全世界的符号;
- 字符编码:将一个字符集转储成二进制的规则,比如:GB212、GBK自带编码规则,可以将字符转储成二进制,而UTF-8、UTF-16则是Unicode的编码规则,负责将Unicode中的字符转储成二进制。
如下图所示:
15. 如何查看字符对应的各种类型编码?
-
方法一: 直接在网站:.php 上搜索即可得某个字符的 ASCII、GB212、BIG-5、GBK、GB1800、Unicode编码;
比如,大写英文字母“W”:
又比如汉字“王”:
还有emoji表情:
-
方法二:上面虽然有常规的编码转换,但是没有关于UTF-16、UTF-8的转换,下面借助c#程序得到字符的UTF-16和UTF-8编码:
class Program {static void Main(string[] args){Cole.WriteLine($W Unicode =>{ConvertToHex(W, Unicode)});Cole.WriteLine($W UTF-16 =>{ConvertToHex(W, UTF-16)});Cole.WriteLine($W UTF-2 =>{ConvertToHex(W, UTF-2)});Cole.WriteLine($W UTF-8 =>{ConvertToHex(W, UTF-8)});Cole.WriteLine($王 Unicode =>{ConvertToHex(王, Unicode)});Cole.WriteLine($王 UTF-16 =>{ConvertToHex(王, UTF-16)});Cole.WriteLine($王 UTF-2 =>{ConvertToHex(王, UTF-2)});Cole.WriteLine($王 UTF-8 =>{ConvertToHex(王, UTF-8)});Cole.WriteLine($😀 Unicode =>{ConvertToHex(😀, Unicode)});Cole.WriteLine($😀 UTF-16 =>{ConvertToHex(😀, UTF-16)});Cole.WriteLine($😀 UTF-2 =>{ConvertToHex(😀, UTF-2)});Cole.WriteLine($😀 UTF-8 =>{ConvertToHex(😀, UTF-8)});}private static string ConvertToHex(string str, string encodingStr){var encoding = System.Text.Encoding.GetEncoding(encodingStr);return ConvertToHex(str, encoding);}private static string ConvertToHex(string str, Encoding encoding){var bs = encoding.GetBytes(str);return 0x string.Join(, bs.ToList().Select(i => i.ToString(X2)));} }
打印的结果:
这里有乱码,是因为控制台使用的ASI编码,即:GBK编码,GBK中没有emoji的字符,所有显示乱码。
-
方法三:我们也可以借助notepad的16进制插件或editplus等编辑器查看,参照:《新版otepad加十六进制查看的插件HexEditor》
最终,我们总结得出英文大写字母“M”、汉字“王”、emoji表情“😀”的各个编码如下:
字符 | ASCII | GB212 | Big5 | GBK | GB1800 | Unicode | UTF-16 | UTF-8 |
---|---|---|---|---|---|---|---|---|
W | 0x57 | 0x57 | 0x57 | 0x57 | 0x57 | 0x57 | 0x57 | 0x57 |
王 | 无 | 0xCDF5 | 0xA4FD | 0xCDF5 | 0xCDF5 | 0x78B | 0x8B7 | 0xE78E8B |
😀 | 无 | 无 | 无 | 无 | 0x949FC6 | 0x1F6001 | 0xDD800DE | 0xF09F9880 |
16. ASI编码、代码页为何物?
先说下代码页:
可以把代码页当做字符集编码的别名,比如:
- 96:代表中文简体;
- 47:代表ASCII;
- 65001:代表UTF-8;
完整的代码页列表,参考微软网站:《代码页标识符》
再来看ASI:
参考:《ASI是什么编码?》
在window环境下经常见到 “ASI”标志,如:
乍一看,ASI和ASCII好像,但它们不是同一个意思。
ASI编码解释:
ASI
并不是某一种特定的字符编码,它表示的是你的系统中设置的国家区域对应的字符编码。比如你的美国同事Bob的系统中ASI编码其实是ASCII编码(ASCII编码不能表示汉字,所以汉字为乱码),而你的系统中(“汉字”正常显示)ASI编码其实是GBK编码,而韩文系统中(“한국어”正常显示)ASI编码其实是EUC-KR编码。
我们打开cmd窗口,查看cmd用的什么字符集编码:
如何修改window操作系统的区域?
看下图:
当我们把区域改成英语(美国)后,重启电脑,再次打开命令行,如下:
然后,打开window记事本,输入汉字“什么”,然后保存,再次打开,发现正常显示中文,但这里能正常显示却是因为保存的格式是UTF-8,如下:
当我们把它保存成ASI时:
这里提示我们,因为里面有Unicode格式的字符(Unicode中有中文字符),而此时的ASI表示的是ASCII码(已设置区域为英语美国),所以会提示我们会有字符丢失的风险,点击确定继续:
#感谢您对电脑配置推荐网 - 最新i3 i5 i7组装电脑配置单推荐报价格的认可,转载请说明来源于"电脑配置推荐网 - 最新i3 i5 i7组装电脑配置单推荐报价格
上一篇:nginx配置文件简介
下一篇:3DMAX中的7个基本建模小窍门
推荐阅读
留言与评论(共有 16 条评论) |
本站网友 到期域名 | 30分钟前 发表 |
UTF-8 上节说到Unicode统一了世界字符的编码标准,但是没有提到这些字符应该怎样转储到计算机中 | |
本站网友 啵一个 | 23分钟前 发表 |
两个字节(如:中文)和三个字节(如:第一辅助平面)的长度,为了将Unicode存储到计算机中出现了UCS-2 | |
本站网友 语轩 | 25分钟前 发表 |
Unicode 在1990年开始研发,1994年正式公布 | |
本站网友 口干舌燥 | 1分钟前 发表 |
2005年月1日推出的Unicode 4.1.0 | |
本站网友 libs | 29分钟前 发表 |
GB212 | |
本站网友 泽地百合 | 21分钟前 发表 |
2005年月1日推出的Unicode 4.1.0 | |
本站网友 完美世界官方网站 | 5分钟前 发表 |
第1辅助平面,多文种补充平面(Supplementary Multilingual Plane | |
本站网友 218219 | 8分钟前 发表 |
ASI编码解释: ASI并不是某一种特定的字符编码,它表示的是你的系统中设置的国家区域对应的字符编码 | |
本站网友 济宁百度推广 | 10分钟前 发表 |
bs.ToList().Select(i => i.ToString(X2)));} } 打印的结果: 这里有乱码,是因为控制台使用的ASI编码,即:GBK编码,GBK中没有emoji的字符,所有显示乱码 | |
本站网友 sodu小说阅读器 | 24分钟前 发表 |
TIP) 40000–DFFFF:第4-1辅助平面,尚未使用 E0000–EFFFF | |
本站网友 eva是什么 | 25分钟前 发表 |
UTF-2)});Cole.WriteLine($W UTF-8 =>{ConvertToHex(W | |
本站网友 抚顺房产网 | 28分钟前 发表 |
另外,我们知道ASCII码的a其实就是0x61(即:97,01000001) | |
本站网友 男性性健康常识 | 16分钟前 发表 |
UTF-16)});Cole.WriteLine($W UTF-2 =>{ConvertToHex(W | |
本站网友 沧海2 | 0秒前 发表 |
因此也可以说:UTF-2是UCS-4的一个子集 | |
本站网友 城市花园 | 11分钟前 发表 |
半角:指ASCII中的字符;全角:指GB212中的字符; 而对于汉字来说,是没有全角和半角的区别的,因为ASCII中本就没有汉字 |