字符集和字符编码以及相关

来源:互联网 发布:如何理解js原型链 编辑:程序博客网 时间:2024/06/11 14:06

为什么写本文

其实在我心中是一直知道有字符编码这么个概念存在的,只是从来没有遇到过关于它的相关问题,而让我有去好好了解它的动力。既然有这篇博文的存在,证明肯定是遇到字符编码的问题了。

事情是这样的,最近公司的产品需要支持短信功能,但是如果想要短信内容支持中文的话则必须使用UCS2编码方式,而程序用的是UTF-8编码方式,那么就需要将UTF-8转换成UCS2编码方式。

就这个问题本身而言是很好解决的,网上很多代码片段就可以解决,使用linux的iconv函数也可以完美地解决。

问题解决之后,特地查阅了相关资料,想了解下这块知识。可是越看越糊涂,原来关于这块知识没有想象的简单。在连续看了不少文章后,终于在阅读了阮一峰老师的博文《字符编码笔记:ASCII,Unicode和UTF-8》和知乎上的《对于字符编码,程序员的话应该了解它的哪些方面?》之后,对字符集和字符编码的相关知识有了点清晰的认识。也建议和我一样对这块知识毫无基础的童鞋先阅读这两篇文章!

那么问题来了,既然已经有以上非常好的文章,我为什么还要写这篇博文呢?一是写在这里,方便自己以后查阅;二是在上面博文的基础之上添加了一些自己的理解。

好,废话不多说,让我们从最基础的概念慢慢说起吧!


什么是字符

从广义上来说,字符(character)是信息的一个单位,文本数据由他们组成,通过它们,文本的内容得以展现和表示,同时它们又是对文本数据进行控制和处理的基本单位

那么在计算机领域到底哪些信息属于字符范畴呢?包括文字、数字符号、图形符号(标点符号)以及控制符号。

因此一个英文字母是一个字符,一个中文汉字是一个字符,一个阿拉伯数字是一个字符,一个标点符号是一个字符,一个回车符或者TAB同样是一个字符。


问题来了,计算机要如何识别和存储字符呢?

众所周知,在计算机的世界,所有的信息都是0/1组合的二进制序列,计算机是无法直接识别和存储字符的。因此,字符必须经过编码才能被计算机处理。也就是说,字符和其它任何信息一样,都是无差别的数字,这些数字只对创建或者能够识别它们的程序来说才有意义,才能正确处理和还原。正因为这样,用汉字写的文档在一个没有汉字处理能力的计算机上显示,结果一定是令人沮丧的。


字符集和字符编码的概念

首先给出结论:字符集和字符编码是两个不同的概念!!!

现在我们知道,字符只有按照一定规则编码,最终表示为0/1二进制序列的形式,才能被计算机处理。因此为了使计算机能够处理字符信息,首先要决定选取那些字符。这样就形成了一个集合,一个表,称为字符表(character repertoire)。但是如果你简单地把这个字符表当做字符集的话,就很片面了,这样就会导致后来你对Unicode字符集以及UTF-8等字符编码之间的一些关系搞不清楚。

那么怎么来理解字符集(character set)的概念比较正统呢?

在理解字符表的基础上,然后,对于任何一个字符表来说,它的每个字符都占有一席之地,并分配有一个唯一的数字,这个数字被称为代码点(code point 或者 code position)。注意,这个代码点仅仅代表字符在字符表中的一个编号,它仅仅是数学意义上的数字,通常和字符在字符表中的位置有关,与对应的字符在计算机内实际的表现形式、存储方法和传输是没有关系的(这些任务是字符编码需要完成的任务)。并且代码点也并不一定是连续的数字。例如,ASCII字符集用0~127这连续的128个代码点分别表示128个字符,而GBK字符集使用区位码的方式为每个字符编号,首先定义一个94X94的矩阵,行称为“区”,列称为“位”,然后将所有国标汉字放入矩阵当中,这样每个汉字就可以用唯一的“区位”码来标识了。例如“中”字被放到54区第48位,因此代码点就是5448。

因此,本质上字符集是已编号字符的有序集合,每个字符的编号我们称之为代码点

OK,知道了什么是字符集之后,那么什么又是字符编码呢?

头脑简单的我,想当然地认为直接将代码点编码为二进制序列的过程就是字符编码了吧!事实证明我是错的!

在我们规定好了一个字符集之后,并不代表计算机一定要将字符对应的代码点本身直接存储!有时候,我们按照一定的规则,根据不同的需求,以及现实计算机的软硬件限制,将字符的代码点再次处理,以更加适应计算机存储、网络传输的需要。字符编码便是规定了如何编码、存储这些字符对应的二进制序列

也就是说,字符编码这个概念其实指的是一个过程 -- 将字符的代码点变成最后可以直接在计算机内存储或者传输的二进制序列的过程

可以想象,最直接简单的字符编码方式就是直接使用字符的代码点,ASCII就是这个这样做的,直接将代码点变成等数值的7比特数字即可,编码值的范围是二进制的000 0000 ~ 111 1111,用十六进制表示就是0x00~0x7F。

但是直接使用字符的代码点容易导致一个问题,就是让人有时候分不清字符集和字符编码的概念。ASCII就可以即代表ASCII字符集,也可以代表ASCII字符编码。同样的,IOS-8859-1、GB2312、GBK,都是即表示了字符集又表示了对应的字符编码。但是Unicode是个例外,因此一定要对字符集和字符编码这两个概念有个清晰的认识,否则后面理解Unicode字符集以及相应的字符编码就会很迷惑,傻傻分不清楚。

另外,需要强调的是,一个字符集可能对应着多种不同的字符编码方法


简述字符集和字符编码发展史

大家最熟悉的字符集肯定是ASCII了。可以这么说,ASCII是现如今所有其它字符集的鼻祖。原始的ASCII字符集包含128个字符,0~31是控制字符,32~63是可打印字符,包含标点符号和数字0~9的符号,64~95包含大写的拉丁字母和另外的标点符号,96~127包含小写的拉丁字母和另外的标点符号。

当计算机传到欧洲的时候,很明显ASCII不足以包含欧洲的所有字符,所以欧洲人民利用未使用的那个字节最高位扩展了ASCII,即新增了128个符号,0~127依然是ASCII,而128~255则是扩展的字符。但是我们知道,欧洲国家太多了,每个国家使用的字符又不同,因此128~255这些扩展字符可以说每个国家是不同的,这就导致了很多新的字符集的诞生,据我了解光ISO 8859字符集就根据不同的国家总共有16个,分别为8859-1~8859-16,简直令人发指。这些字符集有时也被称为扩展ASCII字符集。

原始ASCII字符集和扩展ASCII字符集只使用了一个字符,历史上称为单字节字符集(single byte character set:SBCS)。

当计算机终于传到亚洲,尤其我们中国人民的手里之后,那么要计算机显示我们的中文那是理所当然的需求啊。但是汉字数量庞大, 一个字节肯定是远远不够的了,因此每个字符(汉字)需要更长的字节来编码。但是又要兼容ASCII,这就形成了今天所说的多字节字符。中文字符集主要有两个,一个是GB2313,另一个是GBK,它们都是兼容ASCII字符集的,也就是在这些字符集中,ASCII字符依然使用一个字节来表示,而其他字符使用两个字节来表示。这样的字符集被称为双字节字符集(double byte character set:DBCS)。当然了,可千万别被双字节字符集这个名字所欺骗哦,毕竟这样的字符集实际上是一个混合体,因为ASCII字符依然保持单字节不变。

以上所说的,可以说是字符集和字符编码的战国时代,都是各个国家各自为政的产物。

到了上世纪90年代,终于有组织致力于制定一个全球性的字符集和字符编码标准,至此,Unicode字符集诞生。


Unicode字符集以及相关字符编码

首先,Unicode是个字符集,现在的规模可以容纳100多万个字符,在该编码空间内的任何一个值,都是一个代码点。为了标书一个代码点,可以采用“U”加十六进制整数的方法,如U+004D。我们可以通过Unicode编码表来查询我们的汉字在Unicode字符集中对应的代码点。例如汉字“瑞”的Unicode代码点为U+745E。


参考链接:

《标准C语言指南 -- 字符和字符编码》

《C标准库的setlocale()用法笔记》

《字符编码笔记:ASCII,Unicode和UTF-8》

《对于字符编码,程序员的话应该了解它的哪些方面?》

《Unicode in C and C++: What You Can Do About It Today》

《What Every Programmer Absolutely, Positively Needs To Know About Encodings And Character Sets To Work With Text》

《The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)》

《谈谈字符集与字符编码》

《小结字符集及字符编码问题》

《ANSI是什么编码?》



0 0
原创粉丝点击