字符编码的一些概念与发展

有时候使用开发的时候会被各种编码解码的事情所困扰,尤其是使用Python的时候,Python2和Python3之间又有很多的区别。同时,还有时候,会被IDE报的各种错误弄得眼花缭乱,于是这两期准备好好总结一下字符编码的事情。这一期首先介绍一下常见的一些编码的概念,下一期介绍一下python中如何对编码进行检测和转换。

ASCII码

上世纪五六十年代的时候,人们发明了计算机,用于做一些计算工作。但是,随着慢慢的发展,人们逐渐希望可以使用电子管来表示字符。当然,一个电子管肯定是不够的,必然是多个电子管的组合,那么到底用几个电子管呢?计算机是美国人发明的,英文字母大写加小写一起才52个,再加上10个数字,62个,再加上一些控制字符,大体上也没有太多,7个电子管足够了。于是,一种类似摩尔斯电码的编码出现了,

    美国国家标准学会AMERICAN NATIONAL STANDARDS INSTITUTE: ANSI)提出了一种"Ascii"编码(American Standard Code for Information Interchange,美国信息互换标准代码)其中,前32是控制码,后面的95个分别从小到大表示标点、数字、大写字母,小写字母。这127个字符也被称为“基础ASCII码”。

扩充的ASCII码(GBK,Big5等)

     在ASCII码的基础上,对于不在此范围内的字符进行扩展。对于0~127还是一个字节表示一个英文字符,这是与Unicode编码最大也是最明显的区别。

     对此,各个国家有不同的扩展方式。由此产生了 GB2312(中文)、GBK(中文)、GB18030(中文)、Big5(繁体中文,台湾)、Shift_JIS (日本)等各自的编码标准。不同 ANSI 编码之间互不兼容,当信息在国际间交流时,无法将属于两种语言的文字,存储在同一段 ANSI 编码的文本中。比如对于中文来说的话,中华文化博大精深,1字节(8位)肯定是不能满足需求的,于是,充满智慧的中国人民就想着使用两个字节来表示一个汉字。因此,汉字也被称为“双字节字符集”。汉字编码有GB2312、GBK、GB18030,以下谈一下三者的区别于联系。

    GB2312:当两个字节都大于127时,认为这两个字节组成一个汉字,在这些编码里,我们还把数学符号罗马希腊的字母日文的假名们都编进去了,连在 ASCII 里本来就有的数字、标点、字母都统统重新编了两个字节长的编码,这就是常说的"全角"字符,而原来在127号以下的那些就叫"半角"字符了。

     GBK:只要第一个字节是大于127的,就认为它是一个汉字的开始。总共扩充至20000个左右。

     GB18030:在GBK的基础上加入了几千个少数民族文字。

     以上的三种编码通称为"DBCS"Double Byte Charecter Set 双字节字符集)

     它们之间具有一定的包含关系:

                        GB2312<GBK<GB18030

兼 这三种编码是向下兼容的,不同编码规范中相同的字符总是拥有相同的编码,后面的标准支持更多的字符。

问题: 

      各个国家都像中国这样搞出一套自己的编码标准,结果互相之间谁也不懂谁的编码,谁也不支持别人的编码,连大陆和台湾也分别采用了不同的 DBCS 编码方案——当时的中国人想让电脑显示汉字,就必须装上一个"汉字系统",专门用来处理汉字的显示、输入的问题,但是台湾就必须加装另一套支持 BIG5 编码的"倚天汉字系统"才可以用,装错了字符系统,显示就会乱了套!

      ISO(国际标准化组织)决定解决这个问题,于是他们推出了Unicode编码。

Unicode码

      "Universal Multiple-Octet Coded Character Set",简称 UCS, 俗称 “UNICODE”。意图把地球上所有的字符进行统一编码,采用两个字节来表示所有的字符,即使是原来的半角字符(将它们的高八位置0)。也称为万国码。如汉字“汉”,Unicode码为0x6c49。两个字节可以表示的数的范围是0~65535,刚开始设计Unicode的那群人觉得这(UCS2)对于世界上的几乎所有的语言文字够用了,要知道,常用的汉字才大约6000多个。但是,搞着搞着,发现不太够,于是就想着扩展到UCS4。然而这对于资源是一种极大的浪费。前面有提到,ascii码不论是基础的还是扩展的都有一个特点,那就是对于英文字母和数字依然保持其原有的编码方式。现在世界上使用最流行的语言是英语(虽然使用人数最多的语言是汉语T_T),所以老外肯定不干了。

       在我们的计算机中,内存中使用的是Unicode编码,硬盘中使用的是其它编码。试想如果硬盘中也用的是Unicode编码的话,那将对资源进行怎样的浪费。

       

      上面提到的Unicode码只是一种编码方案,但是并不是存储方案,或者说实现方案。于是,为了考虑到英文字符使用的普遍性,就推出了UTF-8,UTF-6等一系列存储方案。

UTF-8

        UTF-8 (8-bit Unicode Transformation Format)针对Unicode的可变长的字符编码。UTF-816个字节编码Unicode字符。每次传输8位数据!(UTF-16等同理)

      实际表示ASCII字符的UNICODE字符,将会编码成1个字节,并且UTF-8表示与ASCII字符表示是一样的。所有其他的UNICODE字符转化成UTF-8将需要至少2个字节。每个字节由一个换码序列开始。第一个字节由唯一的换码序列,由n位连续的1加一位0组成, 首字节连续的1的个数表示字符编码所需的字节数。Unicode转换为UTF-8时,可以将Unicode二进制从低位往高位取出二进制数字,每次取6位,如上述的二进制就可以分别取出为如下示例所示的格式,前面按格式填补,不足8位用0填补。

    

       

         简单讲,第一个字节的前几位决定了之后的几个字节是一个字符。

        接下来讲一下什么是ANSI,

ANSI  

        当我们使用记事本软件,编辑一段文字之后,点击另存为,这时会弹出一个编码方式,里面显示的是ANSI。

        如果你有在美国的朋友,如果你们同时使用Notepad++,输入一段中文,你会发现,你的美国朋友的电脑上无法正常显示,但是这时如果查看编码方式的话,会发现你们的编码方式都是一样的,都是“ANSI”,这是为什么呢?ANSI编码到底是什么呢?

        

        原来,ANSI并不特指某一种编码方式,它指的是你系统上的默认编码方式,是由你的操作系统决定的,如果你使用的是中文的操作系统,那么ANSI就是“GBK”,如果你使用的是英文的操作系统,那么ANSI就是“ASCII”。对于韩语的操作系统也是如此,如下:

    

   当我们打开Python IDE,使用三种编码方式写入txt,我们会发现只有GBK编码的内容可以正常显示,

        

     不同编码规范中相同的字符总是拥有相同的编码,后面的标准支持更多的字符。

  这也从侧面验证了中文操作系统中的默认编码方式是“GBK”。 

 

记事本的“联通”Bug

  这里借这个有趣的现象,来看一下记事本是如何检测自己的编码方式的。

  当我们在记事本中输入“联通”,然后点击保存,再次打开时,就会发现,原来的联通不见了,替换它的是一堆乱码。

  

    这时如果我们使用“另存为”查看一下该文件的编码方式,发现它并不是ANSI了,转而变成了“UTF-8”,这是为什么呢?

     

   记事本采用的是UTF-8的传输标准,当我们输入“联通”时,我们采用的是“GB”系列的编码,联通的内码是:

    一二字节和三四字节刚好符合UTF-8的两字节模板,这时就会把它翻译成其它字符了。

  此外,在此说一个搞笑的事情,如果在记事本中输入“力挺联通”,也会出现乱码,如下,

  

     这三种编原来码是向下兼容的,不同编码规范中相同的总有相同的编码,后面的标准支持更多的字符。

  当然,这种错误也不是不能消除,出现这种情况,最最根本的原因就是记事本有点笨,对于你输入字符的编码方式检测错误。它并不知道你的编码方式,只能靠猜,如果再多输入几位,就可以使得记事本猜正确的概率大大提升。如下:

接下来讲一下什么是BOM,

BOM

   BOM即byte order mark, 在文件中放置BOM是微软的习惯,在其它系统中会出现问题。不带BOMUTF才是标准格式,UTF-8不需要BOM

     当你新建一个txt,打开“属性”,你会发现它的大小是0字节,但是当把该文件的编码方式改成‘UTF-8’之后,就会发现大小变成了3kb,这多余的3kb实际就是一行文字。BOM纯粹是微软搞的一个多余的东西,默认在首行加入“U+FEFF,告诉编辑器编码方式为utf-8。

 

参考链接https://blog.csdn.net/zxh2075/article/details/53064160

                  http://www.fmddlmyy.cn/text24.html

猜你喜欢

转载自blog.csdn.net/Bubbler_726/article/details/81668782