ASCII GBK UNICODE UCS-2 UCS-4 UTF-8 UTF-16 UTF-32 一次说个明白

ASCII(American Standard Code for Information Interchange,美国信息互换标准代码)

GBK 全称《汉字内码扩展规范》(GBK即“国标”、“扩展”汉语拼音的第一个字母,英文名称:Chinese Internal Code Specification)

Unicode(统一码、万国码、单一码)

UCS 通用字符集(Universal Character Set)

UTF(Unicode/UCS Transformation Format)


1、ASCII码使用指定的7 位或8 位二进制数组合来表示128 或256 种可能的字符。

标准ASCII 码也叫基础ASCII码,使用7 位二进制数来表示所有的大写和小写字母,数字0 到9、标点符号, 以及在美式英语中使用的特殊控制字符。在标准ASCII中,其最高位(b7)用作奇偶校验位。

2、GBK 采用双字节表示,总体编码范围为 8140-FEFE,首字节在 81-FE 之间,尾字节在 40-FE 之间,剔除 xx7F 一条线。总计 23940 个码位,共收入 21886 个汉字和图形符号,其中汉字(包括部首和构件)21003 个,图形符号 883 个。

其中GB 2312 汉字区。即 GBK/2: B0A1-F7FE。首字节在B0-F7之间,尾字节在A1-FE之间,共72个区,每个区94个汉字,共收录 GB 2312 汉字 6763 个(其中D7FA-D7FE 个码位没有定义汉字),按原顺序排列(拼音顺序),B0A1为第一个汉字‘啊’。

3、Unicode是国际组织制定的可以容纳世界上所有文字和符号的字符编码方案。Unicode用数字0-0x10FFFF来映射这些字符,最多可以容纳1114112个字符,或者说有1114112个码位。其中U+4E00~U+9FA5码位,共收入了20902个常用汉字,按笔画顺序排列,U+4E00为第一个汉字‘一’。

4、通用字符集(Universal Character Set,UCS)是由ISO制定的ISO 10646(或称ISO/IEC 10646)标准所定义的标准字符集。UCS-2用两个字节编码,其取值范围为U+0000~U+FFFF,UCS-4用4个字节编码,其取值范围为U+00000000~U+7FFFFFFF,其中 U+00000000~U+0000FFFF和UCS-2是一样的。

UCS-4根据最高位为0的最高字节分成2^7=128个group。每个group再根据次高字节分为256个平面(plane)。每个平面根据第3个字节分为256行 (row),每行有256个码位(cell)。group 0的plane0被称作BMP(Basic Multilingual Plane)。将UCS-4的BMP去掉前面的两个零字节就得到了UCS-2。每个平面有2^16=65536个码位。Unicode计划使用了17个平面(group0的前17个平面),一共有17*65536=1114112个码位。

5、UCS-2和UCS-4只规定了代码点和文字之间的对应关系,并没有规定代码点在计算机中如何存储。 规定存储方式的称为UTF(Unicode Transformation Format),其中应用较多的就是UTF-16和UTF-8了。

5.1 UTF-16由RFC2781规定,它使用两个字节来表示一个代码点。

UTF-16是完全对应于UCS-2的,即把UCS-2规定的代码点通过Big Endian或Little Endian方式 直接保存下来。UTF-16包括三种:UTF-16,UTF-16BE(Big Endian),UTF-16LE(Little Endian)。UTF-16BE和UTF-16LE不难理解,而UTF-16就需要通过在文件开头以名为BOM(Byte Order Mark)的字符 来表明文件是Big Endian还是Little Endian。BOM为U+FEFF则说明UTF-16BE,BOM为U+FFFE则说明UTF-16LE。UTF-16的表达范围是U+0000-U+FFFF。

另外,UTF-16还能表示一部分的UCS-4代码点——U+10000~U+10FFFF。计算方法如下:
从代码点U中减去0x10000,得到U'。这样U+10000~U+10FFFF就变成了 0x00000~0xFFFFF。
用20位二进制数表示U'。 U'=yyyyyyyyyyxxxxxxxxxx
将前10位和后10位用W1和W2表示,W1=110110yyyyyyyyyy,W2=110111xxxxxxxxxx,则 W1 = D800~DBFF,W2 = DC00~DFFF。

例如,U+12345表示为 D8 08 DF 45(UTF-16BE),或者08 D8 45 DF(UTF-16LE)。

但是由于这种算法的存在,造成UCS-2中的 U+D800~U+DFFF 变成了无定义的字符。

5.2 UTF-8由RFC3629定义,它使用非固定字节来表示一个代码点。换算关系如下:

Unicode(hex.)          ║ UTF-8 (binary)
000000 - 00007F ║ 0xxxxxxx
000080 - 0007FF ║ 110xxxxx 10xxxxxx
000800 - 00FFFF ║ 1110xxxx 10xxxxxx 10xxxxxx
010000 - 10FFFF ║ 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
可见,ASCII字符(U+0000~U+007F)部分完全使用一个字节,避免了存储空间的浪费。 而且UTF-8不再需要BOM字节。

另外,从上表中可以看出,单字节编码的第一字节为[00-7F],双字节编码的第一字节为[C0-DF], 三字节编码的第一字节为[E0-EF],四字节编码的第一字节为[F0-F7],多字节的非第一字节为[80-BF]。这样只要看到第一个字节的范围就可以知道编码的字节数,而且根据单个字节就能判断其是否为第一字节。 这样也可以大大简化算法。

5.3 举例说明一下:

‘一’字的Unicode码位是U+4e00,UTF-16LE流编码为 00 4E ,

二进制为 0100 1110 0000 0000 转UTF-8后为 11100100 10111000 10000000 即 UTF-8流编码为 E4 B8 80

'a'的Unicode码位是U+0061,UTF-16LE流编码为 61 00,UTF-8流编码为 61

可见英文用UTF-8只需要1个字节,而中文用UTF-8则需要3个字节,所以英文用UTF-8存储比较省空间,而中文用UTF-8存储则更费空间。

5.4 UTF-32 ,UTF-32其实就是完全对应于UCS-4,同样有BE LE之分,由于太占空间,故而基本无人问津。


6、说了这么多,其实都是抽象的东东,不明白还是不明白,明白了也不知道明白了什么。下面说点具体点的。

我们使用UE来打开我们的*txt文件,这样我们可以方便在文本和二进制之间切换浏览。

我们为1.txt写入字符串 "a啊",用UE打开后可以看到“a啊”字样,切换到二进制可以看到流 61 B0 A1,这时1.txt的编码方式为ASCII编码,大于128的部分则是GBK编码。

我们为1.txt写入流 FF FE 61 00 4A 55,用UE打开后同样可以看到“a啊”字样,切换到二进制可以看到流 FF FE 61 00 4A 55 ,这时1.txt的编码方式为UTF-16LE。

我们为1.txt写入流 FF FE 61 B0 A1 ,用UE打开后发现是乱码,因为B061对应的并非啊字,也并非任何汉字,所以显示的东西根本无法预估。

在Wince中CString对应的字符串,他是一个UTF-16编码的字符串,当我们使用DrawText显示一个字符串时,实际上也是需要该字符串时UTF-16编码的字符串。

当我们用char buf[]="我是什么编码?";申请一个字符串时,buf中存储的是ASCII的编码格式,该字符串的流为 CE D2 CA C7 CA B2 C3 B4 B1 E0 C2 EB A3 BF 00 。

而当我们用wchar wbuf[] = _T("我是什么编码?");申请一个宽字符字符串时,wbuf中存储的是UTF-16LE的编码格式。printf("%x",wbuf[0]);打印的值为6211。

这时候有一种迷惑,是不是char的字符串都是ASCII的,wchar的字符串都是UTF-16的,答案是否定的,char字符串仅仅能说明是单字节的字符串,字符串的每个元素都是一个字节的,wchar字符串仅仅能说明其是双字节的字符串,字符串的每个元素都是两个字节的。

当我们用memcpy(buf,wbuf,sizeof(wbuf)*sizeof(wchar));将wbuf拷贝到buf中时,此时buf字符串中的字符编码依然是UTF-16的。只不过printf("%x",buf[0]);打印值为11了。

这东西果然不是那么容易说清楚的,自己慢慢理解吧。

不管你理不理解,反正我是理解了。

你可能感兴趣的:(算法,存储,character,图形,WinCE,transformation)