理清字符集和字符编码关系
计算机内部由集成电路(Integrated Circuit,IC)构成,IC的所有引脚,只有直流电压0V和5V两个状态。也就是说,IC的一个引脚,只能表示两个状态。正是由于这个原因,决定了计算机的信息只能用二进制数处理。
由于计算机底层使用二进制数来存储和传输数据,而我们人类使用文字、数字和图形符号来表达信息,因此两者之间需要通过某种映射关系来实现。根据映射方向的不同,又可以分为编码和解码。文字、数字等转换成二进制数被称为编码,而二进制数转化为文字、数字和图形符号等称为解码。其中,文字与符号总称为字符(Character),而字符的集合就是字符集(Charset)。常见的字符集包括ASCII字符集、GB2312字符集(简体字符集)、GBK字符集(简繁字符集)和通用字符集(UCS)和Unicode字符集。ASCII
ASCII(American Standard Code for Information Interchange,美国信息交换标准代码)。ASCII字符集包含128个字符,它用8bit表示,其中,第一位用0表示。ASCII编码则是一种将ASCII字符集中的字符映射到二进制数的关系,譬如:A -> 65
。
GB系列
由于中文常用字达到好几千,因此8bit不够用了,增加到16bit,那么就GB2312编码就可以表示2^16=65536字符。GB2312编码就是将这些字符映射到二进制能表示的数,方便计算机存储或传输。
由于汉字种类繁多,除了6000多种简体字体以外,还有繁体字,针对这种情况,GB2312就不能满足了。此时,我们提出了GBK编码方式。
除了简体字、繁体字之外,由于我们是多民族国家,每个民族可能对应一种字符,那么就需要一种新的编码方式来满足这种需求--GB18030。
Unicode
为了整合全世界的所有语言文字,我们的先辈们想出了一个方法Unicode(Universal Mutiple-Octet Coded Character Set),它只是字符集,却没有规定这个二进制该如何存储、传输。其中,它的字符集称为Universal Character Set (UCS),它规定了需要多少字节存储字字符,分别有2个字节和4个字节,各自对应UCS-2、UCS-4。而UTF(Unicode Transformation Format)规定了字符如何传输和存储。UTF又分为UTF-8、UTF-16和UTF-32。我们重点介绍下UTF-8。
根据Huffman编码的思想(最常出现的字符编码尽量的短),以及不同符号使用不同的字节长度表示,因此UTF-8采用了1-4个字节表示一个符号,这种变长的编码方式。它的编码规则如下:
1.对于单字节的符号,字节的第一位置0,后面7位为这个符号的Unicode码。因此,对于英语字母,UTF-8编码和ASCII码是相同的。
2.对于n个字节的字符(n>1),第一个字节的前n位都置为1,第n+1位置为0,后面字节的前两位一律置为10。剩下的没有提及的二进制位,全部为这个符号的Unicode码。
Unicode 和 UTF-8 之间的转换
这里只介绍Unicode转换为UTF-8 ,以汉字 "柯" 为例。已知 "柯" 的Unicode码是 u 67ef
(0110 0111 1110 1111),根据上表,我们可以知道 "柯"这个Unicode对应的UTF-8编码需要3个字节。然后,从0110 0111 1110 1111从由往左依次取数放入到1110 xxxx 10xx xxxx 10xx xxxx中,得到最终的结果是 1110 0110 1001 1111 1010 1111,转换成十六进制是E6 9F AF。
大端与小端
UTF-16、UTF-32是多字节传输,存在字节序的问题,而UTF-8是单字节传输,则不存在字节序的问题。为了帮助大家理解字节序的问题,我还是举个栗子吧,仍来以汉字 "柯" 为例,它的Unicode码是67ef
,它需要两个字节存储,一个字节是67,另一个字节是ef。如果采取大端方式来存储,那么67在前,ef在后,而小端方式刚好相反。
由于UTF-16、UTF-32存在两种存储方式,那么就需要我们标识我们采用了何种存储方式。我们采用在文件开始位置输入特殊字节序列(字节序标记,Byte Order Mark,bom)来标识我们采用了哪种方式,如果文件头两个字节是FF FE(FF比FE大1),则表示采用大端方式;如果文件头两个字节是FE FF,则表示采用小端方式。
欢迎关注微信公众号:木可大大,所有文章都将同步在公众号上。
- objective-C 的OOP(上)--类定义、继承及方法调用
- jQuery打造智能提示插件二(可编辑下拉框)
- Nicholas Christakis:朋友多是由基因决定的?
- WPF中的MatrixTransform
- kvm虚拟化管理平台WebVirtMgr部署-虚拟化环境安装-完整记录(0)
- ruby学习笔记(3)--语法层面的先见之明
- jQuery操作Select
- ruby学习笔记(11)--symbol与hash参数
- zabbix监控-基本原理介绍
- OpenStack构架知识梳理
- mysql操作命令梳理(4)-grant授权和revoke回收权限
- 问未来
- ruby on rails + mysql 开发环境搭建
- CentOS 7.2下安装Mono 5.0
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 一些PHP选项参数相关的函数
- 【Flutter 专题】98 易忽略的【小而巧】的技术点汇总 (六)
- PHP脚本设置及获取进程名
- GlasgowSmile-v2通关笔记
- R语言实现输出文本的多样式
- 学习|Unity3d的导航实现循环线路移动
- 【redis】闲得无聊,来聊聊当下爆火的 redis集群,顺便搭一个玩玩呗
- 【redis入门】Centos下安装redis
- LeetCode精选好题(五)
- 【leetcode两题选手】MySQL类题目(一)
- 【LeetCode每日一题】(8.11)被围绕的区域
- 二叉树的前中后序遍历(迭代法)(带动画)
- 【LeetCode两题选手】算法类题目(8.8)
- 【LeetCode每日一题】(8.9)复原IP地址(回溯)
- 【回溯算法】N叉树相关技巧