Unicode 与 UTF-8的关系

1 篇文章 0 订阅
1 篇文章 0 订阅


要弄清Unicode与UTF-8的关系,我们还得从他们的来源说起,下来我们从刚开始的编码说起,直到UTF-8的出现,我们就会感觉到他们之间的关系
1、ASCII码
我们都知道,在计算机的世界里,信息的表示方式只有0和1,但是我们人类信息表示的方式却与之大不相同,很多时候是用语言文字、图像、声音等传递信息的,那么我们怎样将其转化为二进制存储到计算机中,这个过程我们称之为编码,其实就是一种人为的规定。
我们知道一个二进制有两种状态:”0” 状态 和 “1”状态,这么一个二进制,我们称之为 “一位”,比如我写个1,就代表一个二进制位,写个1000 0000 就代表八个二进制位,那么我们可以发现,一个二进制可以有两种状态,那么它就可以代表两种不同的东西,我们想赋予它什么含义,就赋予什么含义,比如说我规定,“0” 代表 “吃过了”, “1”代表 “还没吃”,这样,我们就相当于把现实生活中的信息编码成二进制数字了,并且这个例子中是一位二进制数字,那么2位二进制数可以代表多少种情况能?对,是四种,2*2,分别是 00、01、10、11,那7种呢?答案是2^7=128,我们知道,在计算机中每八个二进制位组成了一个字节(Byte),计算机存储的最小单位就是字节,字节如下图所示
这里写图片描述
所以早期人们用8位二进制来编码英文字母(最前面的一位是0),也就是说,将英文字母和一些常用的字符和这128中二进制0、1串一一对应起来,比如说 大写字母“A”所对应的二进制位“01000001”转换为十六进制为41
在美国,这128是够了,但是其他国家不答应啊,他们的字符和英文是有出入的,比如在法语中在字母上有注音符号,如é,这个怎么表示成二进制,所以各个国家就决定把字节中最前面未使用的那一个位拿来使用,原来的128种状态就变成了256种状态,比如é就被编码成130(二进制的10000010),为了保持与ASCII码的兼容性,一般最高为为0时和原来的ASCII码相同,最高位为1的时候,各个国家自己给后面的的数字(最高为为1,也就是128以后)赋予他们国家的字符意义,但是这样一来又有问题出现了,不同国家对新增的128个数字赋予了不同的含义,比如说130在法语中代表了é,但是在希伯来语中却代表了字母Gimel(这不是希伯来字母,只是读音翻译成英文的形式)具体的希伯来字母Gimel看下图
这里写图片描述
所以这就成了不同国家有不同国家的编码方式(前128个状态所代表的含义是一样的),所以如果给你一串二进制数,你想要解码,就必须知道它的编码方式,不然就会出现我们有时候看到的乱码
2.Unicode的出现
Unicode为世界上所有字符都分配了一个唯一的数字编号,这个编号范围从 0x000000 到 0x10FFFF(十六进制),有110多万,每个字符都有一个唯一的Unicode编号,这个编号一般写成16进制,在前面加上U+。例如:“马”的Unicode是U+9A6C.
Unicode就相当于一张表,建立了字符与编号之间的联系
这里写图片描述
它是一种规定。但是它没有规定这个编号怎么对应到二进制表示,Unicode本身只规定了每个字符的数字编号是多少。有的人会说了,那我可以直接把Unicode编号直接转换成二进制啊,是的,你可以,但是这个就需要人为的规定了,而Unicode并没有说这样弄,因为除了你这种直接转换成二进制的方案外,还有其他方案,接下来我们会逐一看到。
编号怎么对应到二进制表示呢?有多种方案:主要有UTF-8,UTF-16,UTF-32
1、UTF-32
先来看简单的UTF-32
这个就是字符所对应编号的整数二进制形式,四个字节。这个就是直接转换。
这里需要说明的是,转换成二进制后计算机存储的问题,我们知道,计算机在存储器中排列字节有两种方式:大端法和小端法,大端法就是所要表示的数的高位在低地址处,小端法相反,大端法存储0x01234567如下
这里写图片描述
所以我们在编码方式中有UTF-32BE和UTF-32LE,分别对应大端和小端,让编辑器直接通知操作系统用用户指定的大小端去存储数据
2、UTF-16
UTF-16使用变长字节表示
① 对于编号在U+0000到U+FFFF的字符(常用字符集),直接用两个字节表示。
② 编号在 U+10000到10FFFF之间的字符,需要用四个字节表示,前两个字节叫高代理项,范围是U+DC00到U+DFFF。
如何区别在UTF-16中我是用两个字节来代表还是四个字节来代表我的字符,其实很简单,我只看前两个字节的编号范围,如果是U+D800到U+DBFF,就是四个字节,否则两个字节
3、UTF-8
UTF-8就是使用变长字节表示,顾名思义,就是使用的字节数可变,这个变化是根据Unicode编号的大小有关,编号小的使用的字节就少,编号大的使用的字节就多。使用的字节个数从1到4个不等。
UTF-8的编码规则是:
① 对于单字节的符号,字节的第一位设为0,后面的7位为这个符号的Unicode码,因此对于英文字母,UTF-8编码和ASCII码是相同的
② 对于n字节的符号(n>1),第一个字节的前n位都设为1,第n+1位设为0,后面字节的前两位一律设为10,剩下的没有提及的二进制位,全部为这个符号的Unicode码
举个例子:比如说一个字符的Unicode编码是130,显然按照UTF-8的规则一个字节是表示不了它(因为如果是一个字节的话前面的一位必须是0),所以需要两个字节,所以它的格式为110XXXXX 10XXXXXX
下面我们来具体看看具体的Unicode编号范围与对应的UTF-8二进制格式
这里写图片描述
那么对于一个具体的Unicode编号,具体怎么进行UTF-8的编码呢?
首先将其看做整数,转化为二进制形式(去掉高位的0),然后对照上面的表,看这个二进制长度符合哪一个编号范围所对应的二进制格式的长度(除去红色部分的),然后从右向左依次填入,如果还有X未填,则设为0
比如:“马”的Unicode编号是:0x9A6C,整数编号是39532,对应的二进制是1001 1010 0110 1010,长度为16,刚好符合第三个范围,其格式为:1110XXXX 10XXXXXX 10XXXXXX,将二进制填入进入就为:
11101001 10101001 10101100

总结:UTF-8、UTF-16、UTF-32都是Unicode的一种实现,因为Unicode并没有指定以哪种方式去吧编号转化为二进制,而这三种把Unicode编号对应到了二进制形式,只是对应方法不同而已

本文部分摘自老马说编程公众号和网络资源

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

趣谈编程

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值