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

ASCII 的由来

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

遇上0001 , 终端就换行;                

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

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

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

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

汉字怎么办?

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

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

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

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

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

GB2312对照表

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

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

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

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

Unicode的诞生

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

 . 废除所有地区性的编码    

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

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

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

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

半角字符“A”的表示方法:       

ASCII码:     

Unicode编码:        

汉字“付”的表示方法    

GBK编码:‭‬ ‬    

Unicode编码:‬ ‭‬

UTF8的出现

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

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

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

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

还是以“付”为例:

汉字“付”的表示方法    

GBK编码:‭‬ ‬    

Unicode编码:‬ ‭‬   

UTF-8编码:  

在读取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, ));
      }
  }

【参考资料】

  1. 维基百科-Unicode

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

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

第48篇 字符编码探密--ASCII,UTF8,GBK,Unicode的更多相关文章

  1. 字符编码ANSI和ASCII区别、Unicode和UTF-8区别

    ANSI码ANSI编码是一种对ASCII码的拓展:ANSI编码用0x00~0x7f (即十进制下的0到127)范围的1 个字节来表示 1 个英文字符,超出一个字节的 0x80~0xFFFF 范围来表示 ...

  2. Android中检测字符编码(GB2312,ASCII,UTF8,UNICODE,TOTAL——ENCODINGS)方法(一)

    package com.android.filebrowser;   import java.io.*; import java.net.*;   public class FileEncodingD ...

  3. Android中检測字符编码(GB2312,ASCII,UTF8,UNICODE,TOTAL——ENCODINGS)方法(一)

    package com.android.filebrowser;   import java.io.*; import java.net.*;   public class FileEncodingD ...

  4. Android中检测字符编码(GB2312,ASCII,UTF8,UNICODE,TOTAL——ENCODINGS)方法(二)

    Intent intent = getIntent();         String contentUri = null;         Uri uri =null;         if (in ...

  5. 字符编码之间的转换 utf-8 , gbk等,(解决中文字符串乱码)

    目录 1.背景. 2.编码的理解 3.编码之间的相互转化 4. str类型说明 5. 可以使用的编码类型 6.参考文章 1.背景 Python中与其他程序进行交互时,如果存在字符串交互,特别是字符串中 ...

  6. 字符编码笔记:ASCII,Unicode和UT…

    字符编码笔记:ASCII,Unicode和UTF-8 今天中午,我突然想搞清楚Unicode和UTF-8之间的关系,于是就开始在网上查资料. 结果,这个问题比我想象的复杂,从午饭后一直看到晚上9点,才 ...

  7. 字符编码笔记:ASCII,Unicode和UTF-8(转)

    字符编码笔记:ASCII,Unicode和UTF-8 作者: 阮一峰 日期: 2007年10月28日 今天中午,我突然想搞清楚Unicode和UTF-8之间的关系,于是就开始在网上查资料. 结果,这个 ...

  8. 字符编码简介:ASCII,Unicode,UTF-8,GB2312

    字符编码简介:ASCII,Unicode,UTF-8,GB2312 1. ASCII码 我们知道,在计算机内部,所有的信息最终都表示为一个二进制的字符串.每一个二进制位(bit)有0和 1两种状态,因 ...

  9. [转帖]字符编码笔记:ASCII,Unicode 和 UTF-8

    字符编码笔记:ASCII,Unicode 和 UTF-8 http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html 转帖 ...

随机推荐

  1. PHP实现跨域解决方法

    如果要实现跨域通过设置Access-Control-Allow-Origin来实现跨域. 例如:客户端的域名是client.runoob.com,而请求的域名是server.runoob.com. 如 ...

  2. CJOJ 2484 函数最小值 / Luogu 2085 函数最小值(STL优先队列,堆)

    CJOJ 2484 函数最小值 / Luogu 2085 函数最小值(STL优先队列,堆) Description 有n个函数,分别为F1,F2,...,Fn.定义 \(Fi(x)=Aix^2+Bix ...

  3. Java虚拟机:如何判定哪些对象可回收?

    版权声明:本文为博主原创文章,转载请注明出处,欢迎交流学习! 在堆内存中存放着Java程序中几乎所有的对象实例,堆内存的容量是有限的,Java虚拟机会对堆内存进行管理,回收已经"死去&quo ...

  4. layui中使用autocomplete.js

    前言 在网站找了一大圈都是问题没有答案,记录记录谨防踩坑 layui版本:layui-v1.0.9_rls a(https://github.com/devbridge/jQuery-Autocomp ...

  5. 深入理解 JavaScript(二)

    立即调用的函数表达式 前言 大家学 JavaScript 的时候,经常遇到自执行匿名函数的代码,今天我们主要就来想想说一下自执行. 在详细了解这个之前,我们来谈了解一下"自执行"这 ...

  6. bash脚本基础

    1.bash特性之命令补全与路径补全 命令补全:敲击Tab按键 shell程序在接收到用户执行命令的请求且分析完成后,最左侧字符串将被当作命令去分析$PATH标量所指定的各路径下去查找 查找机制: 1 ...

  7. Pivot Table系列之切片器 (Slicer)

    1. 遇到的问题: 在Excel中,用PivotTable来做数据报告展示: 问题1:在同一个Sheet页里,多个PivotTable如何实现同步刷新? 问题2:在不同Sheet页之间,多个Pivot ...

  8. 使用Visual Studio加断点调试Unity游戏的C#代码

    1.安装Unity5.2.5 2.安装Microsoft Visual Studio 2013 3.打开VS2013,点击Tools | Extensions and Updates,然后在这个界面点 ...

  9. (转)Linux端口nmap和netstat命令

    场景:弄不清楚端口和服务的关系,总觉得这个命令很有用但是还不清楚如何使用 1 linux端口与服务 1.1 安全概述 网络传输安全.操作系统安全.应用软件安全构成了整个网络应用的安全:其中应用软件安全 ...

  10. ibatis 参数和结果的映射处理

    SqlMapClient对象 这个对象是iBatis操作数据库的接口(执行CRUD等操作),它也可以执行事务管理等操作.这个类是我们使用iBATIS的最主要的类.它是线程安全的.通常,将它定义为单例. ...