字符集和编码——程序员必修课

ASCII码

世界上只有两种人——一种会二进制,一种不会二进制~~~
在初学C++时,接触最多的编码就是ASCII码了,全称((American Standard Code for Information Interchange): 美国信息交换标准代码),是老外发明的,老外用的,主要用于显示现代英语和其他西欧语言。

然后C++中的char变量使用的就是ASCII码。用sizeof(char)将会得到1,C++中一个char类型占用一个字节的内存。一字节=8个二进制位。而ASCII码实际只需要7位就可编码,2^7=128,而在标准ASCII中,其最高位(b7)用作奇偶校验位。所谓奇偶校验,是指在代码传送过程中用来检验是否出现错误的一种方法,一般分奇校验和偶校验两种。奇校验规定:正确的代码一个字节中1的个数必须是奇数,若非奇数,则在最高位b7添1;偶校验规定:正确的代码一个字节中1的个数必须是偶数,若非偶数,则在最高位b7添1。

由此引出问题:

都有哪些字符集和编码规则,以及中文怎么输出的,C语言中用char数组是可以正常保存并输出中文的,但似乎有的字会乱码~

字符集&编码

编码

在显示器上看见的文字、图片等信息在电脑里面其实并不是我们看见的样子,即使你知道所有信息都存储在硬盘里,把它拆开也看不见里面有任何东西,只有些盘片。假设,你用显微镜把盘片放大,会看见盘片表面凹凸不平,凸起的地方被磁化,凹的地方是没有被磁化;凸起的地方代表数字1,凹的地方代表数字0。硬盘只能用0和1来表示所有文字、图片等信息。

因此需要制定一系列大家共同认可和使用的编码规则来把01的组合表示成有意义的信息。而上面Ascii码就是一种规则,比如用二进制0100 0001表示字母A,那么信息交换的时候按照编码规则解码就得到了信息本来的意义。

字符集

是一个系统支持的所有抽象字符的集合。字符是各种文字和符号的总称,包括各国家文字、标点符号、图形符号、数字等。

常用的字符集和字符编码

常见字符集名称:ASCII字符集、GB2312字符集、BIG5字符集、GB18030字符集、Unicode字符集等。

ASCII字符集&编码

图片来自百度百科:

老外为了表示更多的欧洲常用字符对ASCII进行了扩展,不要在高位当校验位了,ASCII扩展字符集使用8位(bits)表示一个字符,共256字符。ASCII字符集映射到数字编码规则如下图所示:

在这里插入图片描述

然而中文都不能表示!!!然后来了GBXXXX字符集&编码

GB2312字符集&编码

计算机是老外发明的嘛,发明之后很长一段时间只是应用于美国及西方一些发达国家,ASCII完全满足他们。

但是现在基本家家户户都有计算机,因此必须设计一套编码规则显示中文。于是专家们把ASCII码127号之后东西取消掉,规定:一个小于127的字符的意义与原来相同,但两个大于127的字符连在一起时,就表示一个汉字,前面的一个字节(他称之为高字节)从0xA1用到 0xF7,后面一个字节(低字节)从0xA1到0xFE,这样我们就可以组合出大约7000多个简体汉字了。而连用两个字符表示一个的符号叫"全角"字符,而原来在127号以下的那些就叫"半角"字符了。

C/C++程序运行时那个黑框输入东西时会提示!

上述编码规则就是GB2312

这也解决了我的一个疑问,以前只是听老师说两个字符表示一个汉字,他是怎么知道什么时候是两个字符连起来表示呢~~~

BIG5字符集&编码

Big5,又称为大五码五大码,是使用繁体中文(正体中文)社区中最常用的电脑汉字字符集)标准,共收录13,060个汉字。中文码分为内码及交换码两类,Big5属中文内码,知名的中文交换码有CCCII、CNS11643。Big5虽普及于台湾、香港与[澳门等繁体中文通行区,但长期以来并非当地的国家标准,而只是业界标准。倚天中文系统、Windows等主要系统的字符集都是以Big5为基准,但厂商又各自增加不同的造字与造字区,派生成多种不同版本。2003年,Big5被收录到CNS11643中文标准交换码的附录当中,取得了较正式的地位。这个最新版本被称为Big5-2003。

过度

每个计算机应用广泛的国家都会去制定一套自己的规则,因此肯定会出现一种可能不能做到统一,而现在是互联网时代,相信大家都不止会上国内的网站,懂的都懂,于是一个伟大的创想出现了,Unicode,顾名思义它是一种统一编码的意思,统一码万国码单一码标准万国码

Unicode

在计算机科学领域中,Unicode统一码万国码单一码标准万国码)是业界的一种标准,它可以使电脑得以体现世界上数十种文字的系统。Unicode 是基于通用字符集(Universal Character Set)的标准来发展,并且同时也以书本的形式对外发表。Unicode 还不断在扩增, 每个新版本插入更多新的字符。直至目前为止的第六版,Unicode 就已经包含了超过十万个字符(在2005年,Unicode 的第十万个字符被采纳且认可成为标准之一)、一组可用以作为视觉参考的代码图表、一套编码方法与一组标准字符编码、一套包含了上标字、下标字等字符特性的枚举等。Unicode 组织(The Unicode Consortium)是由一个非营利性的机构所运作,并主导 Unicode 的后续发展,其目标在于:将既有的字符编码方案以Unicode 编码方案来加以取代,特别是既有的方案在多语环境下,皆仅有有限的空间以及不兼容的问题。

Unicode是国际组织制定的可以容纳世界上所有文字和符号的字符编码方案。目前的Unicode字符分为17组编排,0x0000至0x10FFFF,每组称为平面(Plane),而每平面拥有65536个码位,共1114112个。然而目前只用了少数平面。UTF-8、UTF-16、UTF-32都是将数字转换到程序数据的编码方案。

可以这样理解:Unicode是字符集,UTF-32/ UTF-16/ UTF-8是三种字符编码方案。

UTF-8

UTF-8以字节为单位对Unicode进行编码。从Unicode到UTF-8的编码方式如下:

Unicode编码(十六进制)UTF-8 字节流(二进制)
000000-00007F0xxxxxxx
000080-0007FF110xxxxx 10xxxxxx
000800-00FFFF1110xxxx 10xxxxxx 10xxxxxx
010000-10FFFF11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

UTF-8的特点是对不同范围的字符使用不同长度的编码。对于0x00-0x7F之间的字符,UTF-8编码与ASCII编码完全相同。UTF-8编码的最大长度是4个字节。从上表可以看出,4字节模板有21个x,即可以容纳21位二进制数字。Unicode的最大码位0x10FFFF也只有21位。

例1:“汉”字的Unicode编码是0x6C49。0x6C49在0x0800-0xFFFF之间,使用3字节模板:1110xxxx 10xxxxxx 10xxxxxx。将0x6C49写成二进制是:0110 1100 0100 1001, 用这个比特流依次代替模板中的x,得到:11100110 10110001 10001001,即E6 B1 89。

例2:Unicode编码0x20C30在0x010000-0x10FFFF之间,使用4字节模板:11110xxx 10xxxxxx 10xxxxxx 10xxxxxx。将0x20C30写成21位二进制数字(不足21位就在前面补0):0 0010 0000 1100 0011 0000,用这个比特流依次代替模板中的x,得到:11110000 10100000 10110000 10110000,即F0 A0 B0 B0。

UTF-16

UTF-16编码以16位无符号整数为单位。我们把Unicode编码记作U。编码规则如下:

如果U<0x10000,则U的UTF-16编码就是U对应的16位无符号整数(为书写简便,下文将16位无符号整数记作WORD)。

如果U≥0x10000,我们先计算U’=U-0x10000,然后将U’写成二进制形式:yyyy yyyy yyxx xxxx xxxx,U的UTF-16编码(二进制)就是:110110yyyyyyyyyy 110111xxxxxxxxxx。

为什么U’可以被写成20个二进制位?Unicode的最大码位是0x10FFFF,减去0x10000后,U’的最大值是0xFFFFF,所以肯定可以用20个二进制位表示。例如:Unicode编码0x20C30,减去0x10000后,得到0x10C30,写成二进制是:0001 0000 1100 0011 0000。用前10位依次替代模板中的y,用后10位依次替代模板中的x,就得到:1101100001000011 1101110000110000,即0xD843 0xDC30。

按照上述规则,Unicode编码0x10000-0x10FFFF的UTF-16编码有两个WORD,第一个WORD的高6位是110110,第二个WORD的高6位是110111。可见,第一个WORD的取值范围(二进制)是11011000 00000000到11011011 11111111,即0xD800-0xDBFF。第二个WORD的取值范围(二进制)是11011100 00000000到11011111 11111111,即0xDC00-0xDFFF。

为了将一个WORD的UTF-16编码与两个WORD的UTF-16编码区分开来,Unicode编码的设计者将0xD800-0xDFFF保留下来,并称为代理区(Surrogate):

D800-DB7FHigh Surrogates高位替代
DB80-DBFFHigh Private Use Surrogates高位专用替代
DC00-DFFFLow Surrogates低位替代

高位替代就是指这个范围的码位是两个WORD的UTF-16编码的第一个WORD。低位替代就是指这个范围的码位是两个WORD的UTF-16编码的第二个WORD。那么,高位专用替代是什么意思?我们来解答这个问题,顺便看看怎么由UTF-16编码推导Unicode编码。

如果一个字符的UTF-16编码的第一个WORD在0xDB80到0xDBFF之间,那么它的Unicode编码在什么范围内?我们知道第二个WORD的取值范围是0xDC00-0xDFFF,所以这个字符的UTF-16编码范围应该是0xDB80 0xDC00到0xDBFF 0xDFFF。我们将这个范围写成二进制:

1101101110000000 11011100 00000000 - 1101101111111111 1101111111111111

按照编码的相反步骤,取出高低WORD的后10位,并拼在一起,得到1110 0000 0000 0000 0000 - 1111 1111 1111 1111 1111即0xe0000-0xfffff,按照编码的相反步骤再加上0x10000,得到0xf0000-0x10ffff。这就是UTF-16编码的第一个WORD在0xdb80到0xdbff之间的Unicode编码范围,即平面15和平面16。因为Unicode标准将平面15和平面16都作为专用区,所以0xDB80到0xDBFF之间的保留码位被称作高位专用替代。

UTF-32

UTF-32编码以32位无符号整数为单位。Unicode的UTF-32编码就是其对应的32位无符号整数。

字节序

字节序有两种,分别是“大端”(Big Endian, BE)和“小端”(Little Endian, LE)。

根据字节序的不同,UTF-16可被实现为UTF-16LE或UTF-16BE,UTF-32可被实现为UTF-32LE或UTF-32BE。例如:

Unicode编码UTF-16LEUTF-16BEUTF32-LEUTF32-BE
0x006C4949 6C6C 4949 6C 00 0000 00 6C 49
0x020C3030 DC 43 D8D8 43 DC 3030 0C 02 0000 02 0C 30

Unicode标准建议用BOM(Byte Order Mark)来区分字节序,即在传输字节流前,先传输被作为BOM的字符“零宽无中断空格”。这个字符的编码是FEFF,而反过来的FFFE(UTF-16)和FFFE0000(UTF-32)在Unicode中都是未定义的码位,不应该出现于实际传输中。

下表是各种UTF编码的BOM:

UTF编码Byte Order Mark (BOM)
UTF-8 without BOM
UTF-8 with BOMEF BB BF
UTF-16LEFF FE
UTF-16BEFE FF
UTF-32LEFF FE 00 00
UTF-32BE00 00 FE FF

总结

用的最多的就是UTF-8

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值