dingsir的个人博客分享 http://blog.sciencenet.cn/u/dingsir

博文

ASCII码与汉字的机内码、GBK码、18030编码及Uncode编码--我的粗浅理解

已有 3835 次阅读 2023-3-31 17:59 |个人分类:软件杂谈|系统分类:教学心得

ASCII码

在没有特殊控制的情况下,计算机用来存储的单元通常是以字节为 基本单位。计算机在美国发展之初期,使用1个字节(8位0或1)来表示一个英文字母,因此出现了ASCII码,它是现今计算机系统的基础编码之一。即使最高位的没有占用,仅用7位二进制值(十六进制为00到7F,对应十进制值为0到127)就表示了各种英文的字符,包括不可见的控制符(如换行符、C语言的空字符、蜂鸣声等)或可以显示的标点符号、英文字母等。

符号区:32到47,58到64, 91到96,  123到126;

数字区:48到57(对应十六进制为 0x30到0x39);

小写字母:97到122

大写字母:65到90.

英文字母不多,这100来个符号就基本够用了。但后来计算机到了其它国家,比如俄罗期,已经定义的英文字母就不够用了。于是后来将编码在128到256这一段(仍然使用一个字节即8位来表示)用于表示更多的字母,因此出现了扩展的ASCII编码,这部分好象以西里尔字母居多,仍然不包括希腊字母、汉字或日本的假名等。

GB2312-80介绍

我们知道汉字的个数比较多,至少有几千个字算是常用汉字 。那在计算机中,用一个字节是无论如何也表示不了的,至少要用到两个字节来表示一个汉字。

1980年,我国发布了一个国家标准《信息交换用汉字编码字符集-基本集》(标准号GB2312-80)。将常用符号和常用汉字进行了分区编码,大体而言是划成94个 区,每个区有94位,这样就有94*94=有8836个格子可用。标准规定,将区的编号用前一个字节,区内的编码用后一个字节来表示,前后两个字节相连,这样用来表示GB2312-80中所收集的字符,其中大部分汉字都是常用字,因此GB2312影响深远。

标准中1-9区为各种标点、特殊符号、假名、希腊字母、注音字母等。这里面包括了英语中使用的字母与标点符号,形式上与ASCII码的有相似之处,只不过在中国的标准中重新规定了一遍。GB2312中每个符号用两个字节来表示,在汉字的输入法中这些符号通常用全角形式来表示。由于下面所述的原因,GB2312在计算机上使用时它的编码要进行移位以错开ASCII码,因此它们与英文的ASCII虽然形式上相同,但并不是同一个字符。

中间还空了几个区(10到15区)

汉字从第16区开始,第一个汉字是第16区第1个, 即 "啊"字,啊字的编码就是16 01.

为了检索方便,这个标准还提供了部首检索编码的方式,比如锂电池的锂,按部首金字旁五画找到后,再查“里“的七画,就可以找到编码为锂 79 14,即它在79区的第14号格子,编码79 14. 如果是钠,查金字旁后面的4画,可以找到编码36 38,即36区38号。

但是,这样的GB编码如果直接用来保存数据的话,还是有些问题的,最主要的还是前面就已经成熟的ASCII编码的干扰(源远流长的ASCII码地位不可动摇!)。比如前面的钠字,按汉字GB编码来理解,存储成36  38,但如果按ASCII码来解读,36 38还原出来就是符号$&。还有,如果汉字的编码字节是小于33的值,会和ASCII码的不可显示的控制字符冲突。因此,这种编码方案直接应用于存储,得规定文件用何种方案来解码才能使用,实际上文本解读程序往往是根据读到的编码来判断是哪种编码方案,而不是事先指定方案去阅读,因此,直接用它作为保存的编码,解读时就很困惑。当汉字与英文字母混合使用时,这种困惑就更明显了。

为了避免这种情况,早期有人设计了一种交换码,将GB2312的编码,前后字节都加上32, 以避开英文中不能显示的控制字符,这样就不会被错误理解成控制字符了。这种编码称为国标码。

不过这种编码仍然有问题,它还是与ASCII码存在一些重码区域,导致解读出错。比如中国的中字,GB编码是54 48,前后都加上32之后得到86 80, 86对应ASCII码的大写字母V, 80对应ASCII码的大写字母P.这样中字莫名其妙的变成了英文VP,方案仍不够好。

为了进一步规避,有人想出了新办法,将国标码前后两个字节的首位分别都设置成1(数值上相当于加了128), 这样编码中原来0—94的值,分别加上32+128=160(十六进制为0xA0), 移到了160~254这一段,与7位的ASCII码是彻底避开了。这样,汉字就可以与基于英文字母的ASCII码混合使用了。这种编码方案用作中文的计算机内部表示方案,因此称为内码。

在C语言中,如果用字符数组保存了汉字,保存到了文件中,你看到的就是这种内码形式的编码。比如下面这个图中的第一行,你知道是什么意思吗?

内码表示的汉字字串.png

解读的方法比较简单,看到每个字节都比A0大,说明这不是ASCII码,可能是中文或别的。先假定为中文,从第一个开始,每2个字节为一组,每个字节都减去0xA0,再到GB2312-80表格中找一下看看是什么字就行。

0xEF-0xA0=0x4F=79(十进制)0xAE-0xA0=0xE=14(十进制);

0xB5-0xA0=0x15=21,  0xE7-0xA0=0x47=71

0xB3-0xA0=0x13=21.  0xD8-0xA0=0x38=56,

先解这三个吧,查一下GB2312的这张大表,看看79-14, 21-71, 21-56 都是哪些字吧

GB2312-80编码表格.png

原来是 “锂电池“

回过头来看,虽然GB2312规定了编码,但实际上但计算机内部还是要经过转换(前后编码字节各加160)才能使用。而且这样移动之后,双字节的编码方案里,前面部分的编码区域又出现了大量空间没有充分利用。由于还有很 多汉字需要编码,后来出台的GBK编码方案就把这一块用上了。

(有意思的是,当年GB2312-80是强制标准,2007年,在Unicode流行之后,就GB2312就修改成推荐标准了)

GBK方案

在GB2312中,经过移动之后,编码范围是 从第一字节从0xA1-0xF7(中间有一些没有使用),后一字节是0xA1-0xFE。两个字节能够表示的空间还有不少。

为了兼容,GBK方案包容了GB2312移位之后的内码编码范围。同时又找了几块空间来放新的编码,具体来讲,是这样搭配的。

第一字节第二字节
0x81~0xA00x40-0xFE(7F除外)
0xA8~0xFE0x40-0xA0(7F除外)

这样增加了一万多个编码格子,但缺点也是有的,就是某些汉字的第二字节落入了ASCII码的区域,但第一字节仍然都在0x81以上。文本处理器如果不知道这一字节是ASCII码还是GBK码,只要看看它的前一字节和后一字节,如果都比0x80大,那应该就是汉 字编码而不是ASCII码了(ASCII码 都在0x80以下)。因此解读程序是可以正确设置编码方案的。

GB18030方案

这种方案设计没有固定编码的字节数,可以使用1字节,2字节或4字节来表示汉字(没有3个字节的方案)。而且GB18030的前两个字节的方案与GBK方案保持一致,GBK怎么规定的,它是怎么规定。但用四个字节来表示一个汉字时,它能表达的编码有接近160万个,完全能够满足所有汉字表达的需要。

一个字节时,码值从0x00~0x7F, 兼容于ASCII码。

二个字节时,码值 第一字节 0x81~0xFE,第二字节 0x40~0xFE(不包括0x7F)

四个字节时,码值范围是 第1字节0x81~08FE,第2字节0x30~0x39, 第3字节: 0x81~0xFE, 第4字节:0x30~0x39.

用于保存时,GB18030编码就是机内码,直接保存。

它大约相当于是中国发起的一个用于表示全球字符的编码方案,但目前来讲,国际上广泛认可的并不是GB18030方案,而是采用了Unicode方案。

Unicode方案

Unicode方案与GB18030方案是完全不同的两套编码方案。但它们在ASCII码这一小段的编码方案是相同的。它也同样具有非常强大的容量,能够表示100多万个符号。目前已经发布的Unicode标准15版收录的符号(字母、汉字、假名、各国语言的字母、Emoji符号等)就有15万个左右。

Unicode方案,有点象GB2312的是,它们给字符编了码值,但在计算机上存储时,并不是直接采用这个码值,而是使用经过转换的数值才用于存储。大家经常接触的UTF8,UTF16等就是具体存贮Unicode编码时的转换方案。



https://blog.sciencenet.cn/blog-1213210-1382515.html

上一篇:Powershell中如何对多个对象进行筛选?
下一篇:TGDZ 不同语言计算, 增加一种新语言AHK v2
收藏 IP: 210.13.108.*| 热度|

0

该博文允许注册用户评论 请点击登录 评论 (1 个评论)

数据加载中...

Archiver|手机版|科学网 ( 京ICP备07017567号-12 )

GMT+8, 2024-7-18 19:14

Powered by ScienceNet.cn

Copyright © 2007- 中国科学报社

返回顶部