彻底弄懂字符集编码

字符集:字符集是一个字符的集合,每个数字对应一个字符。
字符编码: 编码是字符的存储方案。

比如说:ASCII字符集 就是ASCII码表, 如数字97对应字母a
编码呢,就是如何存储这个97,
你可以使用一个字节来存
你还可以使用两个字节来存
你还可以使用四个字节来存
这下终于搞明白了 原来字符集和编码不是一个东西。

字符集有
ASCII、GB2312、BIG5、GB18030、Unicode。

一、ASCII字符集
ASCII编码
7位二进制存储一个字符,占用1个字节 ASCII字符集用 0-127 表示128个字符

来实验一下

string str = "abc";
byte[] bts = Encoding.ASCII.GetBytes(str);
string aaa = Encoding.ASCII.GetString(bts);
Console.WriteLine("占用字节:" + bts.Length + "," +aaa );
str = "中文";
byte[] ttt = Encoding.ASCII.GetBytes(str);
aaa = Encoding.ASCII.GetString(ttt);
Console.WriteLine("占用字节:" + ttt.Length + "," + aaa);
byte[] kkk = new byte[]{99,201,97};
aaa = Encoding.ASCII.GetString(kkk);
Console.WriteLine("占用字节:" + ttt.Length + "," + aaa);	

输出结果
彻底弄懂字符集编码
第一个把字符串"abc" 用ASCII编码存储为二进制,可以看到占用字节为3个字节 内容为97a 98b 99c,
再用ASCII编码把二进解析字符串得到 abc。
第二个把字符串"中文" 用ASCII编码存储为二进制,在ASCII字符集中无法找到"中文"这两个字符,被存储为63?,再用ASCII编码把二进制解析为字符串,由于二进制存储的是63 63,导致解析后的字符串为??,这时候已经不是乱码问题了,而是数据已经丢失。ASCII编码无法存储 ASCII字符集以外的字符。
第三个把一段二进制用ASCII编码解析为字符串,99c 97a都没问题 201 ASCII字符集中不存在被解析成了 ?字符

二、GB2312字符集
采用GB2312(ANSI)编码
ANSI是每个国家和地区编码标准都不一样,中国是GB2312,韩国是EUC-KR,日本Shift_JIS… 显然这无法国际化。

GB2312字符集可以表示6763个汉字
GBK字符集对GB2312字符集的一次升级 把繁体中文加上去了
GB18030字符集对GBK字符集的一次升级 把各个名族的语言加上去了。

GB2312字符集与ASCII兼容 0-127 与ASCII字符集表述的一致
GB2312编码
小于等于127的部分 采用单字节存储
大于128的部分 采用双字节存储

string str = "abc";
byte[] bts = Encoding.GetEncoding("GB2312").GetBytes(str);
string aaa = Encoding.GetEncoding("GB2312").GetString(bts);
str = "中文a蓌";
byte[] ttt = Encoding.GetEncoding("GB2312").GetBytes(str);
string bbb = Encoding.GetEncoding("GB2312").GetString(ttt);
byte[] kkk = new byte[]{99,201,152};
string ccc = Encoding.GetEncoding("GB2312").GetString(kkk);	
kkk = new byte[]{99,201,120};
string ddd = Encoding.GetEncoding("GB2312").GetString(kkk);	

输出结果
彻底弄懂字符集编码
第一个使用GB2312编码存储"abc" 得到97,98,99共占用3个字节,完全正确,也就是说GB2312编码完全兼容ASCII编码,,如果你用的ASCII编码的文本使用GB2312编码解析一点问题都没有.
第二个使用GB2312编码存储"中文a蓌" 得到 214,208,206,196,97,201,120,占用7个字节。每两个字节表示一个中文,ASCII码字符则用一个字节存储 97,a。再使用GB2312解码二进制,也没有问题

三、Unicode字符集
俗称万国码,字符集中同时包含了英文、中文、韩文、日文。显然这是一个国际化标准。

Unicode字符集对应的编码方式就多了 UTF8、UTF16、UTF32。

UTF8是一种变长的编码,对于一个Unicode的字符会被存储1-4个字节。可以是1个也可能是2个…也可能是4个
实验一下

string str = "abc";
byte[] aa = Encoding.UTF8.GetBytes(str);
str = "一";
byte[] bb = Encoding.UTF8.GetBytes(str);
str = "晓";
byte[] cc = Encoding.UTF8.GetBytes(str);
str = "????";
byte[] dd = Encoding.UTF8.GetBytes(str);
str = "a破晓????";
byte[] ee = Encoding.UTF8.GetBytes(str);

输出结果
彻底弄懂字符集编码
第一个使用UTF8编码存储 “abc” 占用了3个字节,与ASCII编码一致,所以UTF8可以兼容ASCII编码
第二个使用UTF8编码存储"一",占用了3个字节,
第三个使用UTF8编码存储"晓",占用了3个字节
第四个使用UTF8编码存储"????",占用了4个字节
说明utf8是可变长编码。

乱码 “�”,“□”,
经过我的猜测:
“□” 应该是Unicode字符集中有这字符,但是我计算机中未找到相应的字符来显示
“�” 应该是Unicode字符集中压根就没有这个字符,和ASCII中的?的意思有点像

UTF16
要么使用2字节存储 要么使用4字节存储

string str = "abc";
byte[] aa = Encoding.GetEncoding("utf-16").GetBytes(str);
str = "一";
byte[] bb = Encoding.GetEncoding("utf-16").GetBytes(str);
str = "????";
byte[] cc = Encoding.GetEncoding("utf-16").GetBytes(str);

输出结果
彻底弄懂字符集编码
可以看到"abc" 也使用了两个字节来存储
中文"一" 也是使用2字节存储
而"????" 占用了4个字节

UTF32
使用4字节来存储字符

string str = "a";
byte[] aa = Encoding.UTF32.GetBytes(str);
str = "一";
byte[] bb = Encoding.UTF32.GetBytes(str);
str = "????";
byte[] cc = Encoding.UTF32.GetBytes(str);

彻底弄懂字符集编码
可以猜想的到,UTF32应该是效率最高的,牺牲空间来换取时间。

在上述讲到的编码中,显然UTF8最优秀,下次只用此编码了。如果纯英文采用ASCII。GB2312则是在一些以前的程序中使用的,现在应该很少人使用了。

还有一个比较容易出错的就是字符串的概念,有的程序语言包含短字符串和长字符串的概念。
短字符串第一个字节用来存储字符串的长度,也就是第一个字节不能用来解析字符串。短字符串最大255个字符
长字符串则是我们经常使用的。

GB系列字符集
GB2312、GBK、GB18030
GB2312 简体中文
GBK 包含繁体中文
GB18030 包含各个民族的字符。

有些描述可能不准确。如发现请指出。