字符编码---进阶编程篇(六)

本篇文章讲解各种字符编码的使用和区别,使用上来说,几乎都是一致的,理解了底层的字符编码,对于构建跨平台应用来说,是至关注重要的。


再C#中,包含了一下几种主流的字符编码,也是目前为止,用的最多的字符编码了。

  • ASCII
  • ANSI
  • Unicode
  • UTF-8
  • UTF-32

 

先来讲讲历史的东西,最初的计算机是右美国先发明出来的,我们都知道计算机最重要的功能是用于计算,尤其是数据计算,在当时加减法的计算上比人类快很多很多,用的多了就遇见了个大问题,比如我在程序里经过了一系列复杂的计算,现在要把结果显示出来,这个就麻烦了,比如1000,在计算机里是 03 E8 (当然有可能也是 E8 03),然后要显示1000出来(也可以显示"03 E8"),这下真是麻烦了,做不到,显示英文字符也做不到,所以

 

美国国家标准学会主导制定了 ASCII 标准,全称为American Standard Code for Information Interchange ,毕竟计算机是美国发明出来的,并率先在美国大规模发展和使用的,所以标准带个美国也是情理之中的。这张表如下:

 

我们看到除了基本的数字(0-9),大小写的英文之母外,还定义了标点符号,空格,对于一个字节来说,共有256种组合,美国人发现还没有用完,就用剩余的字符设置了一系列控制相关的,这些控制相关的再初期非常有用,用来传送文本,及段落,及制表符的。

指定完上述这张表之后,美国人看到很满意,完全符合了美国的使用习惯和显示需求。要想显示啥就显示啥,连美元符号都有。但是随着计算机的普及,以及传入到欧洲,传入到亚洲使用,就又遇见了一个巨大的问题,字节使用仅剩下了0x80-0xFF没有使用,但是有大量的欧洲字符,亚洲字符需要来表示,怎么办?那就扩充呗。

 

于是乎,诞生了ANSI编码,这个编码规定了如果第一个字节是0x80-0xFF开头的话,就需要结合下一个字节来区分到底是什么字。扩充的字符的数量在128*256 = 32768 ,一下子就扩充了32768个字符,收录了汉子,日本的,以及西欧各国的,事实上来说,比如中文,常用的中文也就4000个汉子左右,所有的中文数量加起来应该超过了80000个字,所以有些生僻的字使用ANSI编码会出现乱码(就是因为字符集不够的原因造成的),而有些嵌入式系统,就是采用了这种编码的机制。

 

下面就来举举例子吧    比如有个字符串   asidhi3535HI    转换成 ANSI 的值  61 73 69 64 68 69 33 35 33 35 48 49 (和ASCII是一致的,所以算是最精简的编码了)

再比如有个字符串  asidhi3535HI是的   转换成 ANSI 的值 61 73 69 64 68 69 33 35 33 35 48 49 CA C7 B5 C4  (也是相当的精简,没有任何多余的编码),我们看到多了4个字节,那就是 CA C7 B5 C4 这个肯定是代表中文的 是的 的意思了。

 

但是ANSI在使用中有2个比较大问题:

  1. 字符处理的时候需要频繁的判断是否一个字节还是二个字节,严重的影响了性能,例如你在统计一串byte[]中的字符个数,那简直是噩梦般的存在,早期的windows都是ansi编码的,开发人员处理字符起来非常的痛苦。
  2. 个数有限,毕竟无法表示世界上全部的字符。

 

所以1988年由Apple及Xerox共同建立了unicode标准,在unicode的标准中,通常包含如下的标准 UTF-8,UTF-16,UTF-32,我们通常所有所说的unicode编码就是UTF-16编码。Unicode编码由2个字节组成,不再将英文列为单个的字节了,这样就大大的提高了字节的使用效率,但是最多仍然不能表示全世界的字节,那就启用unicode的代理功能,对于那些实在是很偏僻的字使用4字节来表示。这样,计算机可以达到性能和节省空间上达到一个比较均衡的点。

所以,在新一代的windows NT核心的开发上,全部换成了unicode编码,对于C#开发,java开发都是采用unicode编码。我们来举例,还是上面的编码

asidhi3535HI是的   转换成ANSI编码   61 73 69 64 68 69 33 35 33 35 48 49 CA C7 B5 C4 

asidhi3535HI是的   转换unicode编码   61 00 73 00 69 00 64 00 68 00 69 00 33 00 35 00 33 00 35 00 48 00 49 00 2F 66 84 76  我们看到长度上来说比上述的ansi编码要长很多,原因就是英文字符也采用了2个字节存储。

 

 

仔细去分析,你很容易得出这样的结论。unicode编码对我们中国人来说,是非常友好的,我们的汉字都是2个字节,编码已经是最高效了,但是对于美国人来说就不公平了,字符里带了一大串无用的 00 ,浪费了存储的硬盘和网络传送的带宽,尤其是带宽,因为编码的问题,原本办理100M的宽带就够了,现在却要用200M,所以为了应对方便的存储数据,方便在互联上上网,加载页面等等操作,都是使用UTF-8标准的编码。

 

UTF-8 的字符编码将一些编码为1个字节,一些编码为2个字节,一些编码为3个字节,一些编码4个字节,这样就可以涵盖全球所有的语言字符了(目前来说,并不是所有的字符都可以在计算机显示,要让计算机显示出来,还有个必要的工作,制定字符集和字体,不然无法显示,但是这个工作是个巨大的工程,所有有些国家的文字没有出现在计算机中),所以UTF-8又叫万国码,这个编码无论是对于美国来说,中国来说,至少在存储和网络传输上来说,是最省空间的。

 

至此,只剩最后一个编码,叫UTF-32了,强制所有的字符都是4字节的,可以表示40亿个字符,显然也是万国码,但是缺点也是显而易见的,巨大的浪费空间。所以只在特殊的情况下才会用到。

 asidhi3535HI是的   转换成UTF-32编码   61 00 00 00 73 00 00 00 69 00 00 00 64 00 00 00 68 00 00 00 69 00 00 00 33 00 00 00 35 00 00 00 33 00 00 00 35 00 00 00 48 00 00 00 49 00 00 00 2F 66 00 00 84 76 00 00

 


接下来就是针对C#的解释了,终于要进入正题了,讲解C#的编码及转码操作

 

首先第一个问题,为什么会存在编码?

只要存在显示和数据存储就存在编码!要不然没有办法显示,你丢给屏幕一串61 73 69 64 68 69 33 35 33 35 48 49 CA C7 B5 C4 它怎么知道要显示 asidhi3535HI是的  呢?

第二个问题,为什么存在乱码?

如果你的文件存储编码是ANSI编码,你却用unicode去读取,当然会位置错乱。

 

用代码来说就是

            string str = "asidhi3535HI是的";
            System.IO.File.WriteAllBytes( "123.txt", Encoding.Default.GetBytes( str ) );


            // 这里的str2将会乱码,不是 asidhi3535HI是的
            string str2 = Encoding.Unicode.GetString( System.IO.File.ReadAllBytes( "123.txt" ) );

 如果想要不乱码,就需要前后的编码对应才可以,同理,别人通过网络给你发了一串字符串。也就是byte[],你在解析的时候一定需要知道里面的编码是什么,这样才能解析。

 

 还有一个重点是什么。str的编码是什么?之前说过C#都是unicode编码的,对了,就是个。

 

 为了说明编码,再举一个例子,就是上述自动生成的123.txt文本,里面的数据是asidhi3535HI是的,你现在要写一个方法,判断这个文件中是不是有“是的”这两个中文字,

            // 需要选择指定的编码解析
            string str2 = Encoding.Default.GetString( System.IO.File.ReadAllBytes( "123.txt" ) );
            if(str2.Contains("是的"))
            {
                // 包含
            }
            else
            {
                // 没有
            }

 

 

 

 到此为止,只要理解了编码的原理,各个编码之间的转换也就很清晰明了了。今天的学习就到这里为止。

 

posted @ 2018-07-28 19:51  dathlin  阅读(1595)  评论(0编辑  收藏  举报