字符编码的基础知识


字符是各种文字和符号的总称,包括各国家文字、标点符号、图形符号、数字等。字符集是多个字符的集合,字符集种类较多,每个字符集包含的字符个数不同,常见字符集名称: ASCII 字符集、 GB2312 字符集、 BIG5 字符集、 GB 18030 字符集、 Unicode 字符集等。计算机要准确的处理各种字符集文字,需要进行字符编码,以便计算机能够识别和存储各种文字。 中文文字数目大,而且还分为简体中文和繁体中文两种不同书写规则的文字,而计算机最初是按英语单字节字符设计的,因此,对中文字符进行编码,是中文信息交流的技术基础。本文将按照字符集的时间顺序讨论几种典型的字符集,选取几种代表性的中文字符集,研究历史由来、特点、技术特征。 汉字编码范围 【字符编码的基础知识】

名称 第一字节 第二字节
GB2312 0xB0-0xF7(176-247) 0xA0-0xFE ( 160-254 )
GBK 0x81-0xFE ( 129-254 ) 0x40-0xFE ( 64-254 )
Big5 0x81-0xFE ( 129-255 ) 0x40-0x7E ( 64-126 ) 0xA1 - 0xFE ( 161-254 )
ASCII 字符集 1 .名称的由来 ASCII ( American Standard Code for Information Interchange ,美国信息互换标准代码)是基于罗马字母表的一套电脑编码系统。 2 .特点 它主要用于显示现代英语和其他西欧语言。它是现今最通用的单字节编码系统,并等同于国际标准 ISO 646 。 3 .包含内容 控制字符:回车键、退格、换行键等。 可显示字符:英文大小写字符、阿拉伯数字和西文符号 4 .技术特征 7 位( bits )表示一个字符,共 128 字符 5 . ASCII 扩展字符集 7 位编码的字符集只能支持 128 个字符,为了表示更多的欧洲常用字符对 ASCII 进行了扩展, ASCII 扩展字符集使用 8 位( bits )表示一个字符,共 256 字符。 ASCII 扩展字符集比 ASCII 字符集扩充出来的符号包括表格符号、计算符号、希腊字母和特殊的拉丁符号。 GB2312 字符集 1 .名称的由来 GB2312 又称为 GB2312-80 字符集,全称为《信息交换用汉字编码字符集 · 基本集》,由原中国国家标准总局发布, 1981 年 5 月 1 日 实施。 2 .特点 GB2312 是中国国家标准的简体中文字符集。它所收录的汉字已经覆盖 99.75% 的使用频率,基本满足了汉字的计算机处理需要。在中国大陆和新加坡获广泛使用。 3 .包含内容 GB2312 收录简化汉字及一般符号、序号、数字、拉丁字母、日文假名、希腊字母、俄文字母、汉语拼音符号、汉语注音字母,共 7445 个图形字符。其中包括 6763 个汉字,其中一级汉字 3755 个,二级汉字 3008 个;包括拉丁字母、希腊字母、日文平假名及片假名字母、俄语西里尔字母在内的 682 个全角字符。 4 .技术特征 ( 1 )分区表示: GB2312 中对所收汉字进行了 “ 分区 ” 处理,每区含有 94 个汉字 / 符号。这种表示方式也称为区位码。 各区包含的字符如下: 01-09 区为特殊符号; 16-55 区为一级汉字,按拼音排序; 56-87 区为二级汉字,按部首 / 笔画排序; 10-15 区及 88-94 区则未有编码。 ( 2 )双字节表示 两个字节中前面的字节为第一字节,后面的字节为第二字节。习惯上称第一字节为 “ 高字节 ” ,而称第二字节为 “ 低字节 ” 。 “ 高位字节 ” 使用了 0xA1-0xF7 ( 把 01-87 区 (88-94 区未有编码 ) 的区号加上 0xA0) , “ 低位字节 ” 使用了 0xA1-0xFE ( 把 01-94 加上 0xA0) 。 5 .编码举例 以 GB2312 字符集的第一个汉字 “ 啊 ” 字为例,它的区号 16 ,位号 01 ,则区位码是 1601 ,在大多数计算机程序中,高字节和低字节分别加 0xA0 得到程序的汉字处理编码 0xB0A1 。计算公式是: 0xB0=0xA0+16, 0xA1=0xA0+1 。 GBK 字符集 1 .名称的由来 GBK 是 GB2312 的扩展,是向上兼容的,因此 GB2312 中的汉字的编码与 GBK 中汉字的相同。 另外, GBK 中还包含繁体字的编码,它与 Big5 编码之间的关系我还没有弄明白,好像是不一致的。 2. 特点 GBK 中每个汉字仍然包含两个字节,第一个字节的范围是 0x81-0xFE (即 129-254 ),第二个字节的范围是 0x40-0xFE (即 64-254 )。 GBK 中有码位 23940 个,包含汉字 21003 个。 BIG5 字符集 1 .名称的由来 又称大五码或五大码, 1984 年由台湾财团法人信息工业策进会和五间软件公司宏碁 (Acer) 、神通 (MiTAC) 、佳佳、零壹 (Zero One) 、大众 (FIC) 创立,故称大五码。 Big5码的产生,是因为当时台湾不同厂商各自推出不同的编码,如倚天码、IBM PS55 、王安码等,彼此不能兼容;另一方面,台湾政府当时尚未推出官方的汉字编码,而中国大陆的 GB2312 编码亦未有收录繁体中文字。 2 .特点 Big5 字符集共收录 13,053 个中文字,该字符集在中国台湾使用。耐人寻味的是该字符集重复地收录了两个相同的字: “ 兀 ”(0xA461 及 0xC94A) 、 “ 嗀 ”(0xDCD1 及 0xDDFC) 。 3 .字符编码方法 Big5码使用了双字节储存方法,以两个字节来编码一个字。第一个字节称为“ 高位字节 ” ,第二个字节称为 “ 低位字节 ” 。高位字节的编码范围 0xA1-0xF9 ,低位字节的编码范围 0x40-0x7E 及 0xA1-0xFE 。 各编码范围对应的字符类型如下: 0xA140-0xA3BF 为标点符号、希腊字母及特殊符号,另外于 0xA259-0xA261 ,存放了双音节度量衡单位用字:兙兛兞兝兡兣嗧瓩糎; 0xA440-0xC67E 为常用汉字,先按笔划再按部首排序; 0xC940-0xF9D5 为次常用汉字,亦是先按笔划再按部首排序。 4 . Big5 的局限性 尽管 Big5码内包含一万多个字符,但是没有考虑社会上流通的人名、地名用字、方言用字、化学及生物科等用字,没有包含日文平假名及片假名字母。 例如台湾视 “ 着 ” 为 “ 著 ” 的异体字,故没有收录 “ 着 ” 字。康熙字典中的一些部首用字 ( 如 “ 亠 ” 、 “ 疒 ” 、 “ 辵 ” 、 “ 癶 ” 等 ) 、常见的人名用字 ( 如 “ 堃 ” 、 “ 煊 ” 、 “ 栢 ” 、 “ 喆 ” 等 ) 也没有收录到 Big5 之中。 GB18030 字符集 1 .名称的由来 GB 18030 的全称是 GB18030-2000 《信息交换用汉字编码字符集基本集的扩充》,是我国政府于 2000 年 3 月 17 日 发布的新的汉字编码国家标准, 2001 年 8 月 31 日 后在中国市场上发布的软件必须符合本标准 2 .特点 GB 18030 字符集标准的出台经过广泛参与和论证,来自国内外知名信息技术行业的公司,信息产业部和原国家质量技术监督局联合实施。 GB 18030 字符集标准解决汉字、日文假名、朝鲜语和中国少数民族文字组成的大字符集计算机编码问题。该标准的字符总编码空间超过 150 万个编码位,收录了 27484 个汉字,覆盖中文、日文、朝鲜语和中国少数民族文字。满足中国大陆、香港、台湾、日本和韩国等东亚地区信息交换多文种、大字量、多用途、统一编码格式的要求。并且与 Unicode 3.0 版本兼容,填补 Unicode 扩展字符字汇 “ 统一汉字扩展 A” 的内容。并且与以前的国家字符编码标准( GB2312 , GB13000.1 )兼容。 3 .编码方法 GB 18030 标准采用单字节、双字节和四字节三种方式对字符编码。单字节部分使用 0×00 至 0×7F 码 ( 对应于 ASCII 码的相应码 ) 。双字节部分,首字节码从 0×81 至 0×FE ,尾字节码位分别是 0×40 至 0×7E 和 0×80 至 0×FE 。四字节部分采用 GB/T 11383 未采用的 0×30 到 0×39 作为对双字节编码扩充的后缀,这样扩充的四字节编码,其范围为 0×81308130 到 0×FE39FE39 。其中第一、三个字节编码码位均为 0×81 至 0×FE ,第二、四个字节编码码位均为 0×30 至 0×39 。 4 .包含的内容 双字节部分收录内容主要包括 GB13000.1 全部 CJK 汉字 20902 个、有关标点符号、表意文字描述符 13 个、增补的汉字和部首 / 构件 80 个、双字节编码的欧元符号等。四字节部分收录了上述双字节字符之外的,包括 CJK 统一汉字扩充 A 在内的 GB 13000.1 中的全部字符。 对汉字进行 hash 为了处理汉字的方便,在查找汉字的时候,我们通常会用到 hash 的方法,那怎么来确定一个汉字位置呢?这就和每种编码的排列有关了,这里主要给出一种 hash 函数的策略。 对于 GB2312 编码,设输入的汉字为 GBword ,我们可以采用公式 (C1-176)*94 + (C2-161) 确定 GBindex 。其中, C1 表示第一字节, C2 表示第二字节。具体如下: GBindex = ((unsigned char)GBword.at(0)-176)*94 + (unsigned char)GBword.at(1) - 161; 之所以用 unsigned char 类型,是因为 char 是一个字节,如果用 unsigend int ,因为 int 是 4 个字节的,所以会造成扩展,导致错误。 对于 GBK 编码,设输入的汉字为 GBKword ,则可以采用公式 index=(ch1-0x81)*190+(ch2-0x40)-(ch2/128) ,其中 ch1 是第一字节, ch2 是第二字节。 具体的, GBKindex = ((unsigned char)GBKword[0]-129)*190 + ((unsigned char)GBKword[1]-64) - (unsigned char)GBKword[1]/128; 怎样判断一个汉字的是什么编码 直接根据汉字的编码范围判断,对于 GB2312 和 GBK 可用下面两个程序实现。 1 、判断是否是 GB2312 bool isGBCode(const string& strIn) { unsigned char ch1; unsigned char ch2; if (strIn.size() >= 2) { ch1 = (unsigned char)strIn.at(0); ch2 = (unsigned char)strIn.at(1); if (ch1>=176 && ch1<=247 && ch2>=160 && ch2<=254) return true; else return false; } else return false; } 2 、判断是否是 GBK 编码 bool isGBKCode(const string& strIn) { unsigned char ch1; unsigned char ch2; if (strIn.size() >= 2) { ch1 = (unsigned char)strIn.at(0); ch2 = (unsigned char)strIn.at(1); if (ch1>=129 && ch1<=254 && ch2>=64 && ch2<=254) return true; else return false; } else return false; } 3 、对于 Big5 它的范围为:高字节从 0xA0 到 0xFE ,低字节从 0x40 到 0x7E ,和 0xA1 到 0xFE 两部分。判断一个汉字是否是 BIG5 编码,可以如上对字符的编码范围判断即可。如何定位呢?那么也想象所有编码排列为一个二维坐标,纵坐标是高字节,横坐标是低字节。这样一行上的汉字个数: (0x7E-0x40+1)+(0xFE-0xA1+1) = 157 。那么定位算法分两块,为 :if 0x40<=ch2<=0x7E: #is big5 charindex=((ch1-0xA1)*157+(ch2-0x40))*2elif 0xA1<=ch2<=0xFE: #is big5 charindex=((ch1-0xA1)*157+(ch2-0xA1+63))*2对于第二块,计算偏移量时因为有两块数值,所以在计算后面一段值时,不要忘了前面还有一段值。 0x7E-0x40+1=63 。 如果判断一个字符是西文字符还是中文字符 大家知道西文字符主要是指 ASCII 码,它用一个字节表示。且这个字符转换成数字之后,该数字是大于 0 的,而汉字是两个字节的,第一个字节的转化为数字之后应该是小于 0 的,因此可以根据每个字节转化为数字之后是否小于 0 ,判断它是否是汉字。 例如,设输入字为 strin ,则, If (strin.at(0) < 0) cout << ” 是汉字 ” << endl; else cout << ” 不是汉字 ” << endl; 编码表 Unicode 字符集 1 .名称的由来 Unicode 字符集编码是 Universal Multiple-Octet Coded Character Set 通用多八位编码字符集的简称,是由一个名为 Unicode 学术学会 (Unicode Consortium) 的机构制订的字符编码系统,支持现今世界各种不同语言的书面文本的交换、处理及显示。该编码于 1990 年开始研发, 1994 年正式公布,最新版本是 2005 年 3 月 31 日 的 Unicode 4.1.0 。 2 .特征 Unicode 是一种在计算机上使用的字符编码。它为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言、跨平台进行文本转换、处理的要求。 3 .编码方法 Unicode 标准始终使用十六进制数字,而且在书写时在前面加上前缀 “U+” ,例如字母 “A” 的编码为 004116 和字符 “?” 的编码为 20AC16 。所以 “A” 的编码书写为 “U+0041” 。 4 . UTF-8 编码
UTF-8 是 Unicode 的其中一个使用方式。 UTF 是 Unicode Translation Format ,即把 Unicode 转做某种格式的意思。 UTF-8 便于不同的计算机之间使用网络传输不同语言和编码的文字,使得双字节的 Unicode 能够在现存的处理单字节的系统上正确传输。 UTF-8 使用可变长度字节来储存 Unicode 字符,例如 ASCII 字母继续使用 1 字节储存,重音文字、希腊字母或西里尔字母等使用 2 字节来储存,而常用的汉字就要使用 3 字节。辅助平面字符则使用 4 字节。 5 . UTF-16 和 UTF-32 编码
UTF-32 、 UTF-16 和 UTF-8 是 Unicode 标准的编码字符集的字符编码方案, UTF-16 使用一个或两个未分配的 16 位代码单元的序列对 Unicode 代码点进行编码; UTF-32 即将每一个 Unicode 代码点表示为相同值的 32 位整数

    推荐阅读