一文搞懂字符编解码

什么是编码?解码?

编码就是字符编码, 通过一定的规则把人类认识的字符映射成二进制串。解码就是把二进制串解密成人类认识的字符。
一文搞懂字符编解码_第1张图片

各种常见的编解码规则,标准

第一个编码标准是ASCII码,8bit,一个字节(byte)就可表示。规定了第0(0000 0000)-- 第127(0111 1111)的128个字符(或动作)的映射关系。
到了后来,中国人民也要使用计算机,但是并不支持汉字呀,怎么办,总不能一直使用英文的吧?
GB2312编码 规定:一个小于127的字符的意义与原来相同,但两个大于127的字符连在一起时,就表示一个汉字,前面的一个字节称之为高字节,后面一个字节称为低字节。
支持:7000多个简体汉字,数学符号、罗马希腊的字母、日文的假名,连在 ASCII 里本来就有的数字、标点、字母都统统重新编了两个字节长的编码,这就是常说的”全角” 字符,而原来在127号以下的那些就叫”半角”字符。GB2312 是对 ASCII 的中文扩展。
注:摘录自知乎这里,感觉看这篇回答就啥都懂了
GBK编码:在GB2312的基础上进一步扩展,低字节可以小于127了,支持繁体字,生僻字。但是跟台湾地区的编码又不一样,台湾的使用BIG5编码。
GB18030:支持少数民族语言。

Latin1:Latin1是ISO-8859-1的别名,有些环境下写作Latin-1。ISO-8859-1编码是单字节编码,向下兼容ASCII,其编码范围是0x00-0xFF,0x00-0x7F之间完全和ASCII一致,0x80-0x9F之间是控制字符,0xA0-0xFF之间是文字符号。
因为ISO-8859-1编码范围使用了单字节内的所有空间,在支持ISO-8859-1的系统中传输和存储其他任何编码的字节流都不会被抛弃。换言之,把其他任何编码的字节流当作ISO-8859-1编码看待都没有问题。这是个很重要的特性,MySQL数据库默认编码是Latin1就是利用了这个特性。ASCII编码是一个7位的容器,ISO-8859-1编码是一个8位的容器。

所以如果我们的数据库使用的编码是Latin1,可以放入汉字,但是当直接获取字符的时候,如果看的字符是乱码,需要先进行Latin1编码encode,再解码decode。

一个例子:

using System;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            string ss = "Rejected:990289010990289010990289040%C3%96%C2%A4%C3%88%C2%AF%C3%81%C3%B7%C3%8D%C2%A8%C2%B9%C3%89%C2%B1%C2%BE%C3%89%C3%A8%C3%96%C3%83%C2%B4%C3%AD%C3%8E%C3%B3%21";
            string result = System.Web.HttpUtility.UrlDecode(ss,System.Text.Encoding.UTF8);
            Console.WriteLine(result);
            //就是这一句,很重要
            System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
            String value = System.Text.Encoding.GetEncoding("GBK").GetString(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(result));
            
            System.Text.Encoding iso = System.Text.Encoding.GetEncoding("ISO-8859-1");
            System.Text.Encoding utf8 = System.Text.Encoding.UTF8;
            System.Text.Encoding GB2312 = System.Text.Encoding.GetEncoding("GB2312");
            byte[] utfBytes = iso.GetBytes(result);
            //因为ISO-8859-1的特性满8bit字节编码,这里不需要编码转换。
            //byte[] gb2312Bytes = System.Text.Encoding.Convert(iso, GB2312, utfBytes);
            string msg = GB2312.GetString(utfBytes);
            Console.WriteLine(msg);
        }
    }
}

Unicode编码: 由于各个国家都有自己的编码规则,且互不相通,所以治乱组织ISO就弄了一个大一统的编码。把所有的的字符都映射到一个个四个字节的二进制串中。
缺点:原先ASCII和Latin1可编的字符,一个字节就够了,现在要4个字节,浪费空间啊。汉字也一样,浪费。所以导致Unicode用的不多。

utf8,utf16:Unicode编码的变种,utf8是一种可变长编码方式。这样它就能更好兼容ASCII和Latin1了,但是它编码汉字是3个字节的,比gb2312要多一个字节。 这也是现在gb2312\gbk编码还很有前途的原因。

下面是unicode与utf8的对应关系,utf8中每个字节以0,110,1110,11110来区分是以几个字节来编码的,10开头的就是中间的。 如果网络传输过程中丢失了数据,就有可能引起解码错误。

  Unicode符号范围 | UTF-8编码方式
     (十六进制) | (二进制)—————————————————————–
0000 0000-0000 007F | 0xxxxxxx
0000 0080-0000 07FF | 110xxxxx 10xxxxxx
0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

utf8和utf16主要是用来作网络传输的编码,utf8就是8bit作为一个数据单位进行传输,而utf16就是16bit作为一个数据单位进行传输。

所以一般一份数据从服务器到客户端显示的过程是这样的:
一文搞懂字符编解码_第2张图片
上面的例子就是做了客户端的部分,先用utf8解码,在用latin1编码,再用gb2312解码,就能得到正确的汉字串了。

总结

  1. 编码是一个字符到二进制串的过程;
  2. 解码是二进制到字符的过程。
  3. 编码和解码很容易记住:就是人类能看懂,把二进制串当成密码。
  4. 所有的编码都兼容ascii,汉字编码从gb2312,gbk,gb18030逐级兼容发展。latin1是欧洲那边采用的编码,因为是满字节的,所有的字符按latin1方式编码,不会丢失数据,最多解码不对的话引起乱码。
  5. utf8,utf16是一个网络传输编码方式。当然保存也是ok的。现在Python就习惯性用utf8。

你可能感兴趣的:(C++,C#,服务器)