第48篇 字符编码探密--ASCII,UTF8,GBK,Unicode

本文追溯了字符编码的发展历程,从ASCII到Unicode,再到UTF-8,详细解析了不同编码方式的特点及适用场景,揭示了计算机如何识别和处理全球各种语言。

原文地址:http://blog.laofu.online/2017/08/22/encode-string/

ASCII 的由来

在计算机的“原始社会”,有人想把日常的使用的语言使用计算机来表示, 我们知道在计算机的世界里面,只有0和1,为了解决尽量多的去表示字符,最终他们决定用8位0和1(一个字节)来表示字符,并且规定当机器读到这几个数据的时候,做出动作或者打印出指定的字符:

遇上0001 0000, 终端就换行;                

遇上0000 0111, 终端就向人们嘟嘟叫;        

遇上‭‭0001 1011‬, 打印机就打印反白的字,或者终端就用彩色显示字母。

这样就形成了最早期的ASCII码表,并把小于32的字符称为“控制字符”,剩下的继续进行编写,一直到127个字符,这样一套完整的字符方案就完成了,终于可以把文字搬到计算机中了。   下图是对应的ASCII码表

 

当大家都在兴奋的可以在电脑的阅读的文章的时候,新的问题又出现了,随着计算机的普及,很多国家都使用了计算机,原来的ASCII码在使用英语的国家可以无障碍的使用,但到了其它国家就无法满足要求了,所以他们决定对后面没有用到的编码(128-255)表示自己国家的语言,并加上了其它的相关的符号,直到编码空间被全部用完,从128-255的字符集称为“ASCII的扩展字符集”。

 

汉字怎么办?   

等到中国人使用电脑的时候,发现已经没有编码供我们来存储对应的汉字了,连扩展的空间都已经被全部占满了。所以我们的前辈们用自己的智慧创造性提出了新的编码格式:

 1. 去除127之外的乱七八糟的字符串和符号    

 2. 如果一个字节且小于127号的字符,与原ASCII码意义相同    

 3. 如果有两个同时大于127的字符则表示一个汉字,所以就会有一个字符会占用两个字节的说法   

 

由于汉字占用两个字节,为了方便区别,我们把前面的字节称为“高位”(从161-247),后面的为“低位”(161-254),这样的一个搭配能表示出大概7000多个数字, 这个编码把所有用到的数字,符号,标点等等都编写进去,其中也有包括对ASCII码的重写,这样就会有我们常说的全角和半角的符号之分。这样的编码格式就是我们常说的“GB2312”   

GB2312对照表    

 

 

博大精深的文化带来的编码麻烦

    当我们庆幸我们的汉字可以在计算中进行传递时,却发现GB2312编码小小的内存空间无法表示“博大精深文化” 需求,很多生僻字无法打印。所以不得不对现有的编码格式就行扩容,在剩余高位和低位的空间中寻找还没有使用的编码,但后来发现还是不够用,因为我们还有繁体字。

 

    经过几次折腾,最终决定放弃对低位的限制,不再要求低位是大于127的值,一旦发现高位是大于127的就认为是汉字,这样又多了大概20000个汉字的表示,这种扩展的编码格式称为:GBK2312

 

    再后来我们发现光有汉字是无法把“中国的文字” 全部表示出来,我们还要表示其它民族的文字,所以又对原来的编码格式进行扩展,最终形成编码:GB18030

 

Unicode的诞生

随着计算机的普及,世界很多国家和很多民族都使用了计算机,各种编码格式也越来越多。随着相互之间的文字交流也越来越频繁,编码格式是成为了主要的障碍,是时候是时候需要一个更为兼容性强大的的编码格式来一统天下,这个编码就是Unicode,创建它的是就是ISO(国际标谁化组织)。ISO当然解决这个问题也比较简单粗暴:

 1. 废除所有地区性的编码    

 2. 重新制定一个能够包含地球上所有的编码     

  在Unicode的制定的时候,硬件已经不再那么的昂贵,所以就大气的把原来的使用一个字节表示(8位),改用成两个字符(16位)表示,其它的字符统一编码,这样理论上一共最多可以表示2^16(即65536)个字符,基本满足各种语言的使用。实际上当前版本的统一码并未完全使用这16位编码,而是保留了大量空间以作为特殊使用或将来扩展。这种大气的方式,虽然统一的编码方式,但也同样带来了问题,由于扩展的字节数,使用原来能用一个字节表示的字母和半角字符的高位都是0,存储空间比原来多了一倍。同样Unincode中,所有的字符都是都是两个字节 而汉字也由原来的两个字符转成了一个字符 –(更多的实现方式不属于此文的讨论之内)     

 

在ASCII码的代码,一个字节是8位,用一个字节来表示一个字符,而汉字用两个字节来表示,所以有汉字可以作为两个字符。 

而在Unicode时代,一个字节还是8位,但是所有的字符表示都是用两个字节,所以汉字也就算成一个字符
 上述16位统一码字符构成基本多文种平面。最新(但未实际广泛使用)的统一码版本定义了16个辅助平面,两者合起来至少需要占据21位的编码空间,比3字节略少。但事实上辅助平面字符仍然占用4字节编码空间,
与UCS-4保持一致。未来版本会扩充到ISO 10646-1实现级别3,即涵盖UCS-4的所有字符。UCS-4是一个更大的尚未填充完全的31位字符集,加上恒为0的首位,共需占据32位,即4字节。理论上最多能表示2^31个字符,
完全可以涵盖一切语言所用的符号。

相关资料:Unicode字符平面映射       

 字符在内存中的表示:

半角字符“A”的表示方法:       
ASCII码: 01000001    
Unicode编码:00000000 01000001       

汉字“付”的表示方法    
GBK编码:‭1011100010110110‬    
Unicode编码:01001110‬ ‭11011000

 

UTF8的出现

      伴随着Unicode的缺点的出现,特别是到互联网的出现,为解决unicode如何在网络上传输的问题,可谓各种实现方法都出现了,具有代表性的就是UTF8和UTF16。这里强调:他们的关系是UTF8和UTF16是Unicode的一种实现方式。

那UTF8又是如何表示字符的呢? UTF8的最大的特点是可伸缩性,具体的编码规则:

1. 对于一个单字节字符,而且首位为0 ,其余的用Unicode补齐。所以对于ASCII内的字符,ASCII的编码与UTF8相同。     

2. 对于n字节的字符,第一个字节的前n位都设为1,第n+1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的unicode码。

  还是以“付”为例:

汉字“付”的表示方法    
GBK编码:‭1011100010110110‬    
Unicode编码:01001110‬ ‭11011000‬   
UTF-8编码:11100100 10111000 10100101

在读取UTF编码的时候,我们只需要读取前面几位有几个1 ,就可以清楚的知道,当前字符占用了几个字节。至于编码的转换,如果理解了原理就很简单了,如果有机会我会写出如何手动去转换字符编码 –(如果我还有动力的写下篇的话~)

.net代码实现一个字符编码转换,这里转出来是二进制的数据,其它格式可以自己扩展:

  public static void Main(string[] args)
  {
      ConvertEncode("Unicode", "GBK", "");
      Console.Read();
  }

  private static void ConvertEncode(string tarEncode, string desEncode, string content, string defaultEncode = "Unicode")
  {
      var byteArr = Encoding.GetEncoding(defaultEncode).GetBytes(content);
      var str = Encoding.Convert(Encoding.GetEncoding(tarEncode), Encoding.GetEncoding(desEncode), byteArr);
      foreach (var b in str)
      {
          Console.Write(Convert.ToString(b, 2));
      }
  }

 

【参考资料】

  1. 维基百科-Unicode

  2. 阮一峰的网络日志-字符编码笔记:ASCII,Unicode和UTF-8

  3. ASCII、Unicode、GBK和UTF-8字符编码的区别联系

源码下载地址: https://pan.quark.cn/s/a4b39357ea24 【运算单元构造实验报告】运算单元是计算机硬件系统中的关键构成部分,主要承担执行算术运算和逻辑运算的任务。在本次实验中,我们着重探讨了带有累加器的运算单元的设计,涵盖了溢出识别、有符号数值与无符号数值运算的差异性,以及采用补码方式进行的加法与减法运算的实现机制。 一、实验目标 1. 掌握运算单元的基本构造,理解带有累加器的运算单元的具体实现途径。 2. 学习并领会溢出检测的机制,能够设计并构建溢出检测电路,用以判定运算结果是否超出了数据类型的表示范畴。 3. 明辨有符号数值和无符号数值运算的不同特性,把握它们在运算过程中各自的处理方法。 4. 熟练掌握基于补码方式的加法与减法运算的执行,理解补码形式下的溢出判定准则。 5. 熟悉运算单元内部的数据传输路线,明晰数据在运算过程中的流转路径。 6. 设计一个能够支持有符号数值与无符号数值运算、补码加法/减法运算以及有符号数值溢出检测的运算单元电路。 二、实验仪器 采用JZYL—Ⅱ型计算机组成原理实验装置,配备2片74181运算单元芯片作为算术逻辑单元(ALU),2片74LS373用作八位D型锁存器,并辅以一些基础门电路和多路选择器来完成电路设计。 三、实验内容 1. 运用片74181构建一个8位运算单元,负责处理数据的高4位与低4位。 2. 设计并实现溢出检测电路,确保在有符号数值与无符号数值的加法运算中均能准确识别溢出状况。 3. 通过74LS373增加累加器功能,使运算结果得以保存。 4. 将所有设计整合,利用多路选择器来支持有符号数值与无符号数值的加法/减法运算。 四、实验电路 1. 8位运算单元由2片74181构成,通过控制...
内容概要:本文围绕“超导磁能储存系统的建模和仿真(Simulink仿真实现)”展开,系统介绍了基于MATLAB/Simulink平台的多种电力电子系统、新能源并网技术、储能控制策略及智能优化算法的建模仿真方法。重点涵盖超导磁能储存系统、光伏逆变器序阻抗建模、虚拟同步发电机(VSG)、风光火储多源协同调频、构网型变流器等关键电力系统组件的动态特性分析与仿真设计,并结合博士/硕士论文复现案例,提供完整的代码与模型资源。同时整合了智能优化算法(如GA、PSO、AFO等)、机器学习、路径规划、信号处理等多学科仿真技术,构建了一个面向科研实践的综合性仿真资源库。; 适合人群:具备一定科研基础,从事电气工程、自动化、能源系统、电力电子与电力系统稳定控制等相关领域研究的研究生、科研人员及工程技术人员。; 使用场景及目标:①开展超导磁能储存系统、新能源并网系统或微电网的建模与稳定性仿真研究;②学习并应用智能优化算法解决电力系统调度、路径规划与多目标优化问题;③复现高水平期刊或学位论文中的仿真模型,提升科研创新能力与论文复现能力;④获取完整仿真代码与模型资源以加速科研项目进展。; 阅读建议:建议读者结合提供的网盘资源,按照目录结构系统学习,优先掌握Simulink建模基础与MATLAB编程技能,重点关注博士/硕士论文复现案例,通过动手实践深入理解复杂系统的建模逻辑与优化算法实现过程。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值