ASCII,GBK,和Unicode的UTF-8,UTF-16,UTF-32阐述

Unicode介绍

Unicode是一张编码表格,包含了世界上每个国家所有的字符对应的二进制数据

计算机只能识别二进制,例如010101001这种二进制数据(计算机使用高低电平表示0和1)。

但是这些二进制人是难以看懂的,于是美国人就用ASCII码制作了一张表,包含了从a,b,c,[email protected]%$等128个字符,差不多半个字节(1111,1111==256 0111,1111==128),为了以后扩充方便就取了一个字节,最高位是0,就这样将英文字符、字符、数字128个包含进去了,下次计算机的0101二进制代码就直接查这个ASCII表就知道对应的字符。

由于世界上并不是只有美国使用计算机,其他国家的字符都不一样,而且我们中国的汉字几万个,一张表存不完。

于是,中国人就发明了GBK编码表,gbk编码规定,计算机不能每次只读一个字节(8个二进制)那么死板,你要先看看第一位是不是为0,要是为0 的话,就当作ASCII码来读入一个字节,不然的话就读入两个字节(汉子太多一个字节存不下,读入两个字节表示汉字就查GBK)。

那么每个国家一个表,这可就尴尬了,相互通信的时候由于解码方式不同就会导致乱码(用ASCII发邮件,计算机查ASCII表转换成对应0101010二进制,接收的人用GBK解码,将010101取查GBK肯定就查不到啊)。

于是,国际组织就发明了一套公用的表unicode编码,将所有国家,所有字符都收进去了,目前有上百万个字符。

字符集和字符编码的区别

字符集和字符编码不是一个概念,字符集定义了文字和二进制的对应关系,为字符分配了唯一的编号,而字符编码规定了如何将文字的编号存储到内存中。有的字符集在制定时就考虑到了编码的问题,是和编码结合在一起的;有的字符集只管制定字符的编号,至于怎么编码,是其他人的事情。

如何将字符编号存入内存中

字符集为每个字符分配了一个唯一的编号,通过这个编号就能找到对应的字符。在编程过程中我们经常会使用字符,而使用字符的前提就是把字符放入内存中,毫无疑问,放入内存中的仅仅是字符的编号,而不是真正的字符实体。

这就抛出了一个问题,如何才能将字符编号放入内存中呢?

对于 ASCII 字符集,这很容易。ASCII 总共包含 128 个字符,用 7 个比特位(Bit)恰好能够存储,不过考虑到计算机一般把字节(Byte)作为基本单元,为了操作方便,我们不妨用一个字节(也就是 8 个比特位)来存储 ASCII。这样虽然浪费了一个比特位,但是读写效率提高了。

但是对于 Unicode,问题就没有这么简单了。Unicode 目前已经包含了上百万的字符,位置靠前的字符用一个字节就能存储,位置靠后的字符用三个字节才能存储。我们可以为所有字符都分配三个字节的内存,也可以为编号小的字符分配一个字节或者两个字节的内存,而为编号大的字符分配三个字节的内存。

方案1:为每个字符分配固定长度的内存

一种方案是为每个字符分配固定长度的内存,并且这块内存要足够大,可以容纳下所有的字符编号。这种方案最简单,直接将字符编号放入内存中即可,不需要任何转换,并且以后在字符串中定位字符、修改字符都非常容易。

目前的 Unicode 已经收录了上百万的字符,至少需要三个字节才能容纳下所有的字符编号。假设字符串"A3中¥"的 Unicode 编码值(十六进制形式)分别是 2A、31、DA49、BB672C,那么它们在内存中的存储形式为:

在几乎所有的字符集中,常用字符的编号往往比较小,罕见字符的编号往往比较大,包括 Unicode 在内。

A和3是 ASCII 编码中的字符,Unicode 为了兼容 ASCII,在设计时刻意保留了原来 ASCII 中字符的编号,所以英文字母和阿拉伯数字在 Unicode 中的编号都非常小,用一个字节足以容纳。中是一个汉字,编号比较大,一般要用两个字节才能容纳。¥可以看做是一个极其少见,或者只有极少数地区才会使用到的字符,这样的字符编号往往比较大,有时候需要三个字节才能容纳。

是人民币符号,是汉字文化的一部分,它和其它汉字一样,实际上是用两个字节存储的,不过这里我们为了演示,故意犯错地说它需要三个字节。

上图中带灰色背景的字节是没有用到的字节,它们就是被浪费掉的一部分内存空间,这就是用固定长度的内存来存储字符编号的缺点:常用字符的编号都比较小,这种方案会浪费很多内存空间,对于以英文为主的国家,比如美国、加拿大、英国等,内存利用率甚至会低于 50%。

方案2:为每个字符分配尽量少的内存

既然上面的方案有缺点,那我们就来改进一下。改进的思路也很明确,就是把空闲的内存压缩掉,为每个字符分配尽量少的字节,例如,A和3分配一个字节足以,中分配两个字节足以,如下图所示:

这样虽然没有了空闲字节,不浪费任何内存空间了,但是又出现新的问题了:如果我不告诉你,你怎么知道2A表示一个字符,而不是2A31或者2A31DA才表示一个字符呢?后面的字符也有类似的问题。

对于第一种方案,每个字符占用的字节数是固定的,很容易区分各个字符;而这种方案,不同的字符占用的字节数不同,字符之间也没有特殊的标记,计算机是无法定位字符的。

这种方案还需要改进,必须让不同的字符编码有不同的特征,并且字符处理程序也需要调整,要根据这些特征去识别不同的字符。

要想让不同的字符编码有不同的特征,可以从两个方面下手:

1) 一是从字符集本身下手,在设计字符集时,刻意让不同的字符编号有不同的特征。

例如,对于编号较小的、用一个字节足以容纳的字符,我们就可以规定这个字符编号的最高位(Bit)必须是 0;对于编号较大的、要用两个字节存储的字符,我们就可以规定这个字符编号的高字节的最高位必须是 1,低字节的最高位必须是 0;对于编号更大的、需要三个字节存储的字符,我们就可以规定这个字符编号的所有字节的最高位都必须是 1。

程序在定位字符时,从前往后依次扫描,如果发现当前字节的最高位是 0,那么就把这一个字节作为一个字符编号。如果发现当前字节的最高位是 1,那么就继续往后扫描,如果后续字节的最高位是 0,那么就把这两个字节作为一个字符编号;如果后续字节的最高位是 1,那么就把挨着的三个字节作为一个字符编号。

这种方案的缺点很明显,它会导致字符集不连续,中间留出大量空白区域,这些空白区域不能定义任何字符。

2) 二是从字符编号下手,可以设计一种转换方案,字符编号在存储之前先转换为有特征的、容易定位的编号,读取时再按照相反的过程转换成字符本来的编号。

那么,转换后的编号要具备什么样的特征呢?其实也可以像上面一样,根据字节的最高位是 0 还是 1 来判断字符到底占用了几个字节。

相比第一种方案,这种方案有缺点也有优点:

  • 缺点就是多了转换过程,字符在存储和读取时要经过转换,效率低;
  • 优点就是在制定字符集时不用考虑存储的问题,可以任意排布字符。

Unicode 到底使用哪种编码方案

Unicode 是一个独立的字符集,它并不是和编码绑定的,你可以采用第一种方案,为每个字符分配固定长度的内存,也可以采用第二种方案,为每个字符分配尽量少的内存。

需要注意的是,Unicode 只是一个字符集,在制定的时候并没有考虑编码的问题,所以采用第二种方案时,就不能从字符集本身下手了,只能从字符编号下手,这样在存储和读取时都要进行适当的转换。

Unicode 可以使用的编码有三种,分别是:

  • UFT-8:一种变长的编码方案,使用 1~6 个字节来存储;
  • UFT-32:一种固定长度的编码方案,不管字符编号大小,始终使用 4 个字节来存储;
  • UTF-16:介于 UTF-8 和 UTF-32 之间,使用 2 个或者 4 个字节来存储,长度既固定又可变。

UTF 是 Unicode Transformation Format 的缩写,意思是“Unicode转换格式”,后面的数字表明至少使用多少个比特位(Bit)来存储字符。

UTF-8

UTF-8 的编码规则很简单:如果只有一个字节,那么最高的比特位为 0;如果有多个字节,那么第一个字节从最高位开始,连续有几个比特位的值为 1,就使用几个字节编码,剩下的字节均以 10 开头。

具体的表现形式为:

0xxxxxxx:单字节编码形式,这和 ASCII 编码完全一样,因此 UTF-8 是兼容 ASCII 的;
110xxxxx 10xxxxxx:双字节编码形式;
1110xxxx 10xxxxxx 10xxxxxx:三字节编码形式;
11110xxx 10xxxxxx 10xxxxxx 10xxxxxx:四字节编码形式。

xxx 就用来存储 Unicode 中的字符编号。

下面是一些字符的编码实例(绿色部分表示本来的 Unicode 编号):

UTF-32

UTF-32 是固定长度的编码,始终占用 4 个字节,足以容纳所有的 Unicode 字符,所以直接存储 Unicode 编号即可,不需要任何编码转换。浪费了空间,提高了效率。

UTF-16

UFT-16 比较奇葩,它使用 2 个或者 4 个字节来存储。

对于 Unicode 编号范围在 0 ~ FFFF 之间的字符,UTF-16 使用两个字节存储,并且直接存储 Unicode 编号,不用进行编码转换,这跟 UTF-32 非常类似。

对于 Unicode 编号范围在 10000~10FFFF 之间的字符,UTF-16 使用四个字节存储,具体来说就是:将字符编号的所有比特位分成两部分,较高的一些比特位用一个值介于 D800~DBFF 之间的双字节存储,较低的一些比特位(剩下的比特位)用一个值介于 DC00~DFFF 之间的双字节存储。

如果你不理解什么意思,请看下面的表格:

位于 D800~0xDFFF 之间的 Unicode 编码是特别为四字节的 UTF-16 编码预留的,所以不应该在这个范围内指定任何字符。如果你真的去查看 Unicode 字符集,会发现这个区间内确实没有收录任何字符。

UTF-16 要求在制定 Unicode 字符集时必须考虑到编码问题,所以真正的 Unicode 字符集也不是随意编排字符的。

总结

只有 UTF-8 兼容 ASCII,UTF-32 和 UTF-16 都不兼容 ASCII,因为它们没有单字节编码。

GB2312、Shift-JIS 等国家(地区)字符集怎么编码

GB2312、GBK、Shift-JIS 等特定国家的字符集都是在 ASCII 的基础上发展起来的,它们都兼容 ASCII,所以只能采用变长的编码方案:用一个字节存储 ASCII 字符,用多个字节存储本国字符。

以 GB2312 为例,该字符集收录的字符较少,所以使用 1~2 个字节编码。

  • 对于 ASCII 字符,使用一个字节存储,并且该字节的最高位是 0;
  • 对于中国的字符,使用两个字节存储,并且规定每个字节的最高位都是 1。

由于单字节和双字节的最高位不一样,所以很容易区分一个字符到底用了几个字节。

宽字符和窄字符(多字节字符)

有的编码方式采用 1~n 个字节存储,是变长的,例如 UTF-8、GB2312、GBK 等;如果一个字符使用了这种编码方式,我们就将它称为多字节字符,或者窄字符。

有的编码方式是固定长度的,不管字符编号大小,始终采用 n 个字节存储,例如 UTF-32、UTF-16 等;如果一个字符使用了这种编码方式,我们就将它称为宽字符。

Unicode 字符集可以使用窄字符的方式存储,也可以使用宽字符的方式存储;GB2312、GBK、Shift-JIS 等国家编码一般都使用窄字符的方式存储;ASCII 只有一个字节,无所谓窄字符和宽字符。

版权声明:本文为CSDN博主「严长生」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/guxiaonuan/article/details/78678043

不同的编码优缺点比较

使用ASCII存储数据,占用一个字节,只能存储英文和数字等128个字符

使用GBK字符集存储数据,占用2个字节,包容ASCII码和中文字符

使用Unicode字符集存储数据,包含世界上所有的字符,目前已经收录了上百万个字符,所以存储数据的方式分为两种:

  • 直接存储,浪费资源,但效率高
  • 根据编码方式进行存储,对Unicode编码进行再编码
    • UTF-8占用1到6个字节
    • UTF-32占用4个字节
    • UTF-16占用2个或4个字节

延伸

用数字信号完成对数字量进行算数运算和逻辑运算的电路称为数字电路,或者数字系统。由于它具有逻辑运算和逻辑处理功能,所以又称数字逻辑电路。

计算机既可以进行数值计算,又可以进行逻辑计算的,这另种计算主要靠CPU来完成,而CPU中重要的负责进行执行运算的部分叫做算数逻辑单元。它就是由数字电路的逻辑门构成的。

逻辑门是数字逻辑电路的基本单元,通过控制高,低电平(分别代表逻辑上的“真”与“假”或二进制中的“1”和“0”),从而实现逻辑运算。

......

延伸文章链接:https://www.cnblogs.com/cnhyk/p/12283585.html

原文地址:https://www.cnblogs.com/cnhyk/p/12284020.html

时间: 2024-08-30 07:24:38

ASCII,GBK,和Unicode的UTF-8,UTF-16,UTF-32阐述的相关文章

ASCII、GBK、unicode、utf-8、iso-8859-1等编码的发展史和相互关系

1.ASCII 很久很久以前,有一群人,他们决定用8个可以开合的晶体管来组合成不同的状态,以表示世界上的万物.他们认为8个开关状态作为原子单位很好,于是他们把这称为"字节". 再后来,他们又做了一些可以处理这些字节的机器,机器开动了,可以用字节来组合出更多的状态,状态开始变来变去.他们看到这样是好的,于是它们就这机器称为"计算机". 开始计算机只在美国用.八位的字节一共可以组合出256(2的8次方)种不同的状态. 他们把其中的编号从0开始的32种状态分别规定了特殊的

Native2asciiUtil 文本文件转UNICODE编码文件(支持UTF-8,Unicode,UTF-16BE,ANSI|ASCII,GBK)

package com.ctl.util; import java.io.File; import java.io.IOException; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Set; /** * * @author Administrator * @Description \u5C06\u6587\u672C\u6587\u4EF6\u8F6C\

浅谈ASCII码、unicode编码、UTF-8编码的区别

字符集:是一堆字符组成的集合,用来指定字节或者字符串映射成二进制的规则 (在计算机中存储的,无论是字节还是字符串都是以二进制模式存储的.) ASCII编码和Unicode编码的区别: ASCII编码是1个字节,而Unicode编码通常是2个字节(2-4个字节). 字母A用ASCII编码是十进制的65,二进制的01000001: 字符0用ASCII编码是十进制的48,二进制的00110000,注意字符'0'和整数0是不同的: 汉字"中"已经超出了ASCII编码的范围,用Unicode编码

论GBK、Unicode、UTF-8的区别

记得自己刚学计算机的时候,经常听到GBK,Unicode,UTF-8等编码,当时懵懵的,总是把GBK和Unicode搞混,那么这些编码到底有什么区别呢? 这还得从计算机的来由说起. 很久很久以前,当计算机刚刚发明的时候,由于计算机只能接受2进制的数据,美国人民为了交流方便,约定了一套编码,他们用8根可以开合晶体管来表示不同的状态,一 共可以组成 2^8 种不同的状态,他们将A.B.C.D ...这些字母以及一堆奇奇怪怪的符号 (刚好128个字符,半个字节的长度,为了防止以后需要为新的符号编码,于

ASCII编码和Unicode编码

ASCII编码和Unicode编码的区别:ASCII编码是1个字节,而Unicode编码通常是2个字节. 字母A用ASCII编码是十进制的65,二进制的01000001: 字符0用ASCII编码是十进制的48,二进制的00110000,注意字符'0'和整数0是不同的: 汉字中已经超出了ASCII编码的范围,用Unicode编码是十进制的20013,二进制的01001110 00101101. 你可以猜测,如果把ASCII编码的A用Unicode编码,只需要在前面补0就可以,因此,A的Unicod

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

很久很久以前,有一群人,他们决定用8个可以开合的晶体管来组合成不同的状态,以表示世界上的万物.他们看到8个开关状态是好的,于是他们把这称为”字节“.再后来,他们又做了一些可以处理这些字节的机器,机器开动了,可以用字节来组合出很多状态,状态开始变来变去.他们看到这样是好的,于是它们就这机器称为”计算机“. 开始计算机只在美国用.八位的字节一共可以组合出256(2的8次方)种不同的状态. 他们把其中的编号从0开始的32种状态分别规定了特殊的用途,一但终端.打印机遇上约定好的这些字节被传过来时,就要做

位/字节/ASCII/UTF-8/GBK/GB2312/Unicode 扫盲

1个字节(Byte)=8位 bit  1位就是计算机中的 1 或0 比如10进制1 ,ASCII码是49,二机制是: 00110001 它占用一个字节. ASCII码:一个英文字母(不分大小写)占一个字节的空间,一个中文汉字占两个字节的空间.一个二进制数字序列,在计算机中作为一个数字单元,一般为8位二进制数,换算为十进制.最小值0,最大值255.如一个ASCII码就是一个字节. UTF-8编码:一个英文字符等于一个字节,一个中文(含繁体)等于三个字节. Unicode编码:Unicode是一种编

编码方式ASCII、GBK、Unicode、UTF-8比较

心情: 写代码经常遇到中文乱码问题,很烦,一气之下总结了各种编码方式(O`-`O)!! 文章内容深度较浅,详细了解可到下链接:https://blog.csdn.net/QuinnNorris/article/details/78705723; 总结了以下几种编码方式: ASCII.GBK(GB2312.GB18030).Unicode.UTF-8 ASCII American Standard Code for Information Interchange 最早的编码,一个字符一个字节.没有

GB2312、GBK、Unicode和UTF-8编码介绍

 汉字编码知识点 ASCII码是西欧编码的方式,采取7位编码,所以是2^7=128,共可以表示128个自负,包括34个字符,(如换行LF,回车CR等),其余94位为英文字母和标点符号及运算符号等.在计算机中,一个ASCII码占8位,最高位(bit7)用作奇偶校验.奇校验规则:正确的代码一个字节中1的个数必须是奇数,若非奇数,则在最高位b7补一个1:偶校验规则:正确的代码一个字节中1的个数必须是偶数,若非偶数,则在最高位b7补一个1. 为了识别双字节的字符,比如汉字或日文韩文等都是占用2个字节

qt中文格式GBK.UTF-8,unicode 之间的转换

QTextCodec *gbk = QTextCodec::codecForName("GB18030");QTextCodec *utf8 = QTextCodec::codecForName("UTF-8");QString g2u = gbk->toUnicode(m_pUserSpi.m_mapInstruments.find(str1.toStdString())->second->InstrumentName); QString as