技术的变化可谓日新月异,不管前端还是后端,新的框架和模式都层出不穷,可能我们今天还在学习一个新框架的使用,明天就看见了它没落的影子,到底什么才是“不变的技术”?

我认为构成“技术世界”的“组件”是不变的,正如再漂亮的大厦也离不开钢筋和水泥一样!今天我要给大家分享的就是“技术大厦”的基础组件之一:“字符串编码”。

想必大家应该都知道一些常用的编码格式比如 ASCII、Unicode、UTF-8、GB2312,Base64 等,为什么需要这些编码格式?我们应该如何选择编码?为什么会产生乱码?这些都是本 Chat 要分享给大家的干货。

通过本场 Chat,你将在以下几个方面获益:

  1. 这个信息世界为什么需要字符串编码
  2. 字符串编码的演进过程
  3. 常见的字符串编码格式解析和乱码原因分析

编码小故事——“联通”不如“移动”

一直以在编码界都流传着一个传说,那就是“联通”不如“移动”,这个故事讲的是什么呢?各位可以跟我一起来试一下。

首先我们打开 Windows 系统自带的记事本程序,在里面输入“联通”两个字,然后保存这个文件。

保存好以后,我们再双击打开这个文件,这个时候可以看到下面的样子:

为什么我们的“联通”两个字变了样呢?

OK,我们再重复一遍刚才的动作,新建一个文本文件但是这次我们输入的两个字是“移动”,保存再打开,请看下图:

“移动”还是那个“移动”,是不是觉得还是“移动”厉害一点呢?

OK,先不给大家揭秘,大家可以带着“联通”这个问题继续往下看。

为什么字符串需要被编码?

大家都知道在计算里面所有的存储和运算都要使用 0 和 1 来表示。说的直白一点,计算机只认识0 和 1,也就是所谓的二进制。但是人类的信息世界里,语言表达抽象出来却是一系列的字符串,为了让计算机能够对这些字符串进行运算、传输、存储、显示,就必须得有一种翻译的方法把字符串翻译成 0 和 1,这些翻译字符串的方法我们就叫字符串编码

所以我们之所以要对字符串进行编码,根本的原因就是为了让计算机理解我们的语言,编码是一座翻译的“桥梁”。

编码的演进历史

1946 年美国人发明了世界上第一台计算机,为了能够在计算机里面表达英文、数字和一些其他符号,1967 年美国有关的标准化组织就发布了ASCII 编码标准,ASCII 编码是一种单字节的编码方法,一个字节有 8 个位,所以 ASCII 编码理论上可以表示 256 个字符,实际上只用了低 7 位来表示,总共可以表达128 个字符,这对于当时的美国人来说是足够用的。

随着计算机的普及,除了美国以外,其他国家也陆陆续续开始使用计算机,这个时候大家就发现多数国家的语言所包含的字符集都有非常多的符号,举个例子,我们中国人平时所用的汉字就有几千个,用 ASCII 编码标准是远远不足以对所有的文字和符号进行编码,因此人们就开始研究其他的编码标准。

ISO-8859-1是 ISO(国际标准化组织)在 ASCII 编码的基础上制定的扩展 ASCII 编码标准,涵盖了大多数的西欧语言字符,仍然是单字节编码,它总共可以表示256 个字符

GB2312 由中国国家标准总局 1980 年发布,1981 年 5 月 1 日开始实施的一套国家标准,标准号是 GB 2312—1980。GB2312 收录 7445 个字符,其中汉字 6763 个,编码适用于汉字处理、汉字通信等系统之间的信息交换,中国大陆几乎所有的中文系统和国际化的软件都支持 GB 2312。

GBK全称是《汉字内码扩展规范》,是中国国家技术监督局为 Windows95 所制定的新的汉字编码规范,它是对 GB2312 的扩展,加入了更多的汉字,兼容 GB2312。

Unicode是 1988 年由 Apple 和 Xerox 共同建立的一套标准字符集,Unicode 的全称是 Universal Code ,1994 年正式发布,目的是想把全世界的各种语言和符号都能够使用一套统一的编码来表示,它有 3 个实现标准一个是UTF-16,一个是UTF-8,另外一个是UTF-32,在后面的章节我们再进行详细的编码介绍。

以上就是计算机字符串编码的一个简单的演进过程,其目的都是为了能够更好地让计算机理解世界上各个地区各个民族的语言和符号,能够让计算机为我们服务,我相信未来将会有更好的编码方式出现。

常用的字符串编码格式解析

  • ASCII 编码
  • Unicode 编码
  • GB2312、GBK、GB18030 编码

ASCII 编码

标准 ASCII 编码是一种非常简单的编码格式,它使用一个字节的低 7 位来表示一个字符,总共可以表示 128 个字符,下面列举几个字母和符号的编码对应关系。

字符 二进制编码
a 0110 0001
b 0110 0010
c 0110 0011
< 0011 1100
> 0011 1110

详细的 ASCII 编码表可以自行百度,标准 ASCII 编码了所有的大写和小写字母,数字 0 到 9、标点符号,以及在美式英语中使用的特殊控制字符。让我们举一个列子,"hello!" 如果用 ASCII 编码表示的话,如下图所示:

可以看出 ASCII 编码的最高位都是 0,使用了一个字节的低 7 位。ASCII 编码的特点是计算简单占用的内存空间少一个字符占用一个字节,但是能表示的字符相当有限。

Unicode 编码

严格的意义来说 Unicode 只是一种字符集,这个字符集包括了世界上所有的字符,它把每一个字符都用数字编了一个唯一编号,比如“你”字在 Unicode 中的编号是 0x4F60(十六进制),“好”字在 Unicode 中的编号为 0x597D,感兴趣的同学可以查询: unicode.org ,Unicode 字符集是一个非常庞大的集合,现在可容纳 100 多万个符号。但是 Unicode 并没有规定编码如何在计算机中存储,比如,汉字“严”的 Unicode 是十六进制数 4E25,转换成二进制数足足有 15 位 (100111000100101) ,也就是说,这个符号的表示至少需要 2 个字节,其他的符号也许需要更多字节,或者更少的字节,因此就有了以下几种具体的编码实现:

  • UTF-16

UTF-16 是 Unicode 字符集的其中一种编码格式,这种编码格式的特点是将每个字符固定编码为 2 个字节,也就是常说的双字节编码,大家对比一下 ASCII 编码就很容易知道 UTF-16 编码的优势,它总共可以使用 16 位,也就是理论上能表达 65536 个字符,比起 ASCII 可正是进步了不少,这样世界上大部分语言和符号都能用统一的编码表示,能够减少各种不同编码之间的转换,就好比世界上的所有人如果都说中国话,那么就不需要中间的翻译了。我们看下"hello!"如果用 UTF-16 编码是怎么表示的:

可以看出对于同样的英文字母字符串编码,Unicode 的使用的空间是 ASCII 的两倍。

UTF-16 的特点是在满足大多数字符编码的情况下简化了编码方案,但是对于只用单字节编码的字符来说无疑浪费了很多存储空间。

  • UTF-8

UTF-8 编码是 Unicode 字符集使用的另外一种编码格式,也是目前使用较为广泛的一种编码格式。这种编码格式的特点是:它是一种变长的编码方案,使用 1~4 个字节来存储,既然是变长编码那么。

计算机如何知道三个字节是分别表示三个字符还是代表的是一个字符呢?

为此 UTF-8 采用了一个简单的编码规则:

如果一个字符的 Unicode 码能用一个字节表示,那么最高的比特位为 0,后面 7 位为这个符号的 Unicode 码。

如果一个字符的 Unicode 码必须用多个字节才能表示,那么第一个字节从最高位开始,连续有几个比特位的值为 1,就使用几个字节编码,剩下的字节均以 10 开头。

具体的表现形式为:0xxxxxxx:单字节编码形式,这和 ASCII 编码完全一样110xxxxx 10xxxxxx:双字节编码形式1110xxxx 10xxxxxx 10xxxxxx:三字节编码形式11110xxx 10xxxxxx 10xxxxxx 10xxxxxx:四字节编码形式

以上表格我们可以看出 UTF-8 是根据字符的 Unicode 码的范围,把字符编码为一个字节或者两个字节、或者三个字节。因为大多数汉字的 Unicode 码都是在第三个区间,所以使用UTF-8 来编码汉字所占用的存储空间一般为 3 个字节对英文字母的编码和 ASCII 码一致都是占用一个字节

  • UTF-32

    UTF-32 是 Unicode 字符集的另外一种实现方案,是把每个字符固定编码为:4 个字节,虽然编码方案简单,但是在大多少情况下浪费了存储空间,所以实际上应用的并不多。

GB2312 、GBK、GB18030 编码

GB2312 编码是中国国家标准总局发布的一套国家标准,主要用于对汉字的编码处理,它对汉字是双字节编码,对编号 127 之前的字符是兼容 ASCII 编码的,总共包含了 682 个非汉字图形字符和 6763 个汉字,它所收录的汉字已经覆盖中国大陆 99.75%的使用频率。

GB2312 总的编码范围是:A1A1-FEFE,其中汉字编码范围:B0A1-F7FEGB2312 采用了分区的表示方法,总共分为 94 个区,每个区 94 位,

01-09 区收录除汉字外的 682 个字符。

10-15 区为空白区,没有使用。

16-55 区收录 3755 个一级汉字,按拼音排序。

56-87 区收录 3008 个二级汉字,按部首/笔画排序。

88-94 区为空白区,没有使用。

每个字符采用两个字节表示,第一个字节为“高字节”,对应 94 个区;第二个字节为“低字节”,对应 94 个位

举例来说,“啊”字是 GB2312 编码中的第一个汉字,它位于 16 区的 01 位,所以它的区位码就是 1601,这种码也就是我们常说的区位码。

区位码的区号和区位分别加上 0xA0,就是该字符对应的 GB2312 编码

比如:啊字的 GB2312 编码就是
0x10(区号)+0xA0 = 0xB0 (高字节)0x01(区位)+0xA0 = 0xA1 (低字节)

所以啊字的 GB2312 的编码就是:B0A1感兴趣的同学可以自行百度 GB2312 的详细编码表。

GBK:1995 年 12 月发布的汉字编码国家标准,是对 GB2312 编码的扩充,对汉字采用双字节编码,GBK 字符集共收录 21003 个汉字,包含国家标准 GB13000-1 中的全部中日韩汉字,和 BIG5 编码中的所有汉字,GBK 兼容 GB2312,也就是说用 GB2312 编码的汉字可以用 GBK 来解码。

G18030:2000 年 3 月 17 日发布的汉字编码国家标准,是对 GBK 编码的扩充,覆盖中文、日文、朝鲜语和中国少数民族文字,其中收录 27484 个汉字。GB18030 字符集采用单字节、双字节和四字节三种方式对字符编码。兼容 GBK 和 GB2312 字符集,在实际的系统中没有得到广泛应用。

总结

ASCII 编码是最简单的编码方式,只支持英文、数字和一些特殊符号,不支持对中文进行编码,占用存储空间小,适合西欧国家语言编码。

GB2312 和 GBK 是专为处理中文编码开发,都是双字节编码,兼容 ASCII,但是 GBK 的编码范围更大,能处理的汉字更多,所以在处理汉字的场景里面通常会选择 GBK 编码。

GBK 是完全兼容 GB2312 的。

UTF-16 和 UTF-8 都支持中文和英文编码,相对来说 UTF-16 的编码效率更高,字符到字节的转换更为简单,但是多数情况下会浪费存储空间,不适合网络传输。UTF-8 由于是可变长的编码方式,兼容 ASCII 编码,在存储和效率上做了折中,更适合网络传输,和多语言混合编码,所以我们大多数情况下会选择使用 UTF-8 编码。

最后讲几个常见的出现乱码的原因。

编码和解码使用的编码方案不是同一套或者不兼容

比如:使用 GBK 对“abc 我喜欢”这个字符串进行编码存储,但是解码的时候用的却是 ASCII 解码,那么最后输出的字符串就是一串我们不认识的"乱码",或者牛头不对马嘴,为什么?看下图:

因为 GBK 是双字节编码,一个字符保存为 2 个字节存储,但是 ASCII 是单字节编码方式,解码的时候同样是按照一个字节一个字节对应码表解码,原来用两个字节表示的字符在解码的时候被拆分成一个字节一个字符自然就不对了。

编码和解码都是同一套方案,但是编码不支持对应的字符

比如:将中文和中文符号通过 ASCII 编码后,所有的字符都会变成“?”,这是因为 ASCII 在进行编解码的时候对于所有不在码值范围的字符都会统一用 3f 表示,看下图:

多次的编码和解码过程中出现不匹配

大家再看一下下面的图就明白了:

综上三种常见的乱码情况,我们应该如何来解决呢?我的心得是:

  1. 在保存字符串的时候务必搞清楚对应的编码,那么读取文本的时候也就一定要按照保存的时候编码来进行解码,也就是说编解码要匹配或者兼容。
  2. 尽量使用 UTF-8 进行字符串的编解码
  3. 出现乱码的时候,要分析每一次编码和解码的地方,就像第三个例子,如果光从头和尾看的话,编解码是一致的但是中间的错误解码导致了整个结果出错。

给大家推荐一些网站和工具:

中文编码查询:http://www.mytju.com/classcode/tools/encode_gb2312.asphttps://www.qqxiuzi.cn/bianma/zifuji.phphttp://tool.chinaz.com/tools/unicode.aspx

进制转换:http://tool.oschina.net/hexconvert/

ASCII 码表:http://tool.oschina.net/commons?type=4

文本编辑器推荐使用 UE,可以查看文本对应的 16 进制,非常方便。大家自己百度搜索下载。

怎么现在大家知道为什么“联通”乱码了吗,可以用 UE 打开去分析一下哟!

通过本 Chat 的学习,我相信你应该对于字符串编码有了一个新的认识,知道在日常的研发工作中如何去选择字符串编码格式,对于一些乱码的问题能在心中有一个基本的判断。

万丈高楼平地起,打好坚实的基础,成就美好未来,加油!

阅读全文: http://gitbook.cn/gitchat/activity/5d3fb5369ae5c111d9a456e0

您还可以下载 CSDN 旗下精品原创内容社区 GitChat App , GitChat 专享技术内容哦。

勿在浮沙筑高台之“字符串编码”相关推荐

  1. 万丈高楼平地起,勿在浮沙筑高台--论程序员基础知识的重要性

    万丈高楼平地起,勿在浮沙筑高台,所谓的基础知识,就好比是盖房子要打地基一样,没有坚实牢固的地基,房子就没有稳定性,根基不稳,早晚会对自己的发展造成重大的影响.程序员只有将基础知识知识牢记在心,才能产生 ...

  2. 勿在浮沙筑高台——转VC学习入门

    引言:      沉寂了三个多星期,一直在写这个东西.      首先声明,我不是高手.我只学过几年VC,水平尚不及高手万分之一,但自认已经算是入门了.在此想和打算学VC却又苦于不知如何下手的朋友们聊 ...

  3. 浮沙筑塔——protues仿真C51程序之LED灯闪烁

    零.闲话三两 不得不惊叹于计算机功能的强大且全面,分明与51单片机是不同宗不同源的两样机种,其效用却能在计算机上完美复现.在21世纪的新世代人类眼里,"电脑"或许只是"网 ...

  4. 小程序 url 对象转字符串编码传参 url 字符串转对象解码接收参数

    url 对象转字符串编码传参 let info = encodeURI(JSON.stringify(this.data.info));wx.navigateTo({url: '/pages/part ...

  5. String字符串编码解码格式

    https://blog.csdn.net/qq_35241080/article/details/83001149 //2 如何识别字符串编码 public static String getEnc ...

  6. python中文字符串编码_浅谈python下含中文字符串正则表达式的编码问题

    前言 Python文件默认的编码格式是ascii ,无法识别汉字,因为ascii码中没有中文. 所以py文件中要写中文字符时,一般在开头加 # -*- coding: utf-8 -*- 或者 #co ...

  7. Javascript对象的查询字符串编码

    您是否知道将Javascript对象编码为可通过GET请求传递的string的快速简便的方法? 没有jQuery ,没有其他框架-仅是纯Javascript :) #1楼 如果要递归转换嵌套对象,并且 ...

  8. Swift3.0语言教程获取字符串编码与哈希地址

    Swift3.0语言教程获取字符串编码与哈希地址 Swift3.0语言教程获取字符串编码与哈希地址,以下将讲解字符串中其它内容的获取方法. 1.获取字符串编码 在NSString中可以使用2个属性获取 ...

  9. python3中字符串编码常见种类_Python基础篇—标准数据类型—String字符串编码问题...

    我要开始写String编码问题了...脑壳疼.. 在String字符串的第一篇末尾有留一个坑,就是关于中文字符串编码.整个编码的故事说起来都是很费劲的,我也只能把我所知道的梳理整理一下,在日常敲码过程 ...

最新文章

  1. VMware Fusion指定虚拟机IP
  2. 堆排序时间复杂度_堆排序算法
  3. 为什么Java 8中不再需要StringBuilder拼接字符串
  4. 中科曙光服务器怎么装系统_如何给服务器装系统
  5. 单链表删除、修改和查找
  6. 初探EntityFramework——空Code First模型
  7. JAVA分布式篇3——Dubbo
  8. 编写数据驱动的单元测试的代码
  9. MyBatis的XML配置文件(三)
  10. UE4_下载源码并编译
  11. 【Android智能硬件开发】【010】安卓读写串口
  12. Activex控件是什么?
  13. 自己制做python3.6精简绿色版
  14. HEVC之CU\PU\TU
  15. U盘格式化导致存储空间变小的解决方法汇总
  16. C++信息学奥赛一本通(T1413:确定进制)
  17. The server of Nginx(二)——Nginx基本功能配置
  18. ida符号文件路径设置
  19. 焦点损失函数 Focal Loss 与 GHM
  20. 【分享opengl教程】

热门文章

  1. ECharts实例(4)
  2. JavaScript-网页特效
  3. 用代码过中秋,python海龟月饼你要不要尝一口?
  4. 12位串行AD转换器TLC2543与单片机的接口设计与编程
  5. C++程序设计基础之(第三章)函数
  6. win10开机启动文件夹路径
  7. 计算机段落格式解释,职称计算机考试Word教程:Word段落格式
  8. 《Java程序设计》第三周学习总结
  9. ZBrush中的三种对称类型的完美运用
  10. pytorch项目报错:ImportError: no module named “cd“