基础概念
字符
字符是各种文字和符号的总称,包括各国家文字、标点符号、图形符号、数字等
字符集
一个操作系统支持的字符的集合。
字符编码和解码
将每个字符都设置一个唯一编号,编码就是将字符集中的字符编号以一定形式转化为字节存储下来,解码则反之,将存储的字节转换为某个字符集的字符编号。
关于屏幕上的字符显示,其实显示的是字形码,将某字符集的编号和字形一一对应(忽略字体),则可以在屏幕上显示字符。
例如ASCII和GB系列,它们即是字符集也是编码方案,即表示它们的字符编码和存储的一样;但Unicode只是字符集,UTF-8一系列是编码方案。
ASCII
ASCII使用一个字节表示一个字符,包含所有大小写英文字母、数字0-9和一些符号等,实际只用了7位,最高位固定位0,范围为0x00~0x7F(0~127),共表示128字符。常用于美国和以英语为主的国家。
有个经常用到的技巧:由于大小写字母对应的ASCII的值相差32,所以小写字母转大写字母只需要 小写字母的ASCII值减去32 就可得到该字母的大写。(a是97,A是65)
ISO-8859-1
别名Latin1,常用于描述北美和西欧语言,也是使用一个字节描述一个字符,范围为0x00~0xFF(0~255),其中0x00~0x7F和ASCII码一样,0x80-0x9F之间是控制字符,0xA0-0xFF之间是一些文字符号。
中文编码(GB系列)
GB2312
全称《信息交换用汉字编码字符集·基本集》,是中国第一个汉字编码标准,GB是国标的首字母,共收录了 6763 个常用的汉字和字符,其中一级汉字3755个, 二级汉字3008个;
同时收录了包括 拉丁字母、 希腊字母、 日文、平假名及片假名字母、 俄语在内的682个字符。
GB2312是双字节编码,一个字符用两个字节表示,第一个字节称为高位字节(0xA1~0xF7),第二个字节称为低位字节(0xA1~0xFE)。为了兼容ASCII,两个字节的最高位都为1。
整个字符集分为94(01~94)个区,每个区又分为94(01~94)位,第88~94区未使用。
区位码
总共有 94 个区,每个区含有 94 个汉字或者字符,每个汉字或者字符都对应一个分区编号和分区内的位置编号,称为区位码。
国标码
国标码也叫交换码,用于交换文件所使用的编码,在早期,不同的操作系统可能使用不同的内码,如果它们之间要交换文件,则会发生乱码的现象,当时的解决方法是交换文件之前先转成交换码再交换,接收者收到之后再转成内码。交换码是比较早期的一种方案,目前系统大都采用内码作为交换码。
ASICII 码为 0-31 的这 32 个字符是不可显示的字符,为了避免和这些字符的码点冲突,将 分区编号和分区内位置编号都加上32 ,把这个转换的结果称为国标码。
比如:汉字 "中" 字分区编号是 54,分区内位置编号是 48,加上 32 之后,分区编号是 54 + 32 = 86,分区内位置编号是 48 + 32 = 80,所以 "中" 字 的国标码是 86 80
内码
国标码和ASICII码还是存在一定的重复,比如"中" 字的国标码是 86 80,对应第一个字节是 86,第二个字节是80,而在ASICII 码中它们分别代表大写字母V和大写字母P,这就无法区分它们到底是一个汉字,还是两个字母。
为了兼容ASCII,把国标码中的每个字节的最高位置为 1,还是以 "中" 字为例,它的国标码是 86 80,加上128后,第一个字节是86 + 128 = 214,第二个字节是 80 + 128 = 208,转化成 16 进制是 0xD6 0xD0。
国标码的每个字节都加上 128 后,得到国标码的机内码,简称内码,汉字是以内码的形式在计算机中存储和传播的。
GBK
全称 《汉字内码扩展规范》,共收录了两万多个汉字和字符,完全兼容 GB2312,增加了一些人名、繁体字、日语和朝鲜语中的汉字,利用了GB2312未使用的编码空间。GBK并不是国家标准。
编码范围: 第一个字节 0x81–0xFE,第二个字节 0x40–0xFE。
GB18030
全称国家标准GB 18030-2005《信息技术 中文编码字符集》,共收录70244个汉字和字符,在GBK的基础上增加了中日韩语中的汉字和少数名族的文字及字符,完全兼容 GB2312,基本兼容 GBK。
GB18030 是变长多字节字符集,每个字或字符可以由一个,两个或四个字节组成。编码空间庞大,最多可定义161万个字符。
为了兼容GBK,前两个字节和GBK保持一致。
Unicode(万国码)
Unicode编码系统为表达任意语言的任意字符而设计。它使用4字节的数字来表达每个字母、符号,或者表意文字(ideograph)。每个数字代表唯一的至少在某种语言中使用的符号。
Unicode仅仅是字符集,它只规定了字符的唯一编号,编码是用UTF-8、UTF-16等编码格式。
实际上,如果每个字符都用Unicode规定的4字符,那绝对是非常浪费的,所以UTF系列对Unicode做了一定压缩和转换。
Unicode共分为17个plane(组),plane0称为基本平面,其他的称为扩展平面,数字范围是0~0x10FFFF,每一个数字,就是一个代码点(Code point)。
UTF-8
变长编码格式(1~4字节),是Unicode的一种实现。将代码点转为二进制bit,不够位数左侧补0。为了解决字符间分隔,即到底几个字节表示一个字符,采用字节的最高位连续1的个数决定。如下表,这种格式比较省空间,第一段和ASCII相同
代码段 | 编码 |
0x000000~0x00007F | 0xxxxxxx |
0x000080~0x0007FF | 110xxxxx 10xxxxxx |
0x000800~0x00FFFF | 1110xxxx 10xxxxxx 10xxxxxx |
0x010000~0x10FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx |
UTF-16
UTF-16使用2个或4个字节,其中2个字节表示基本平面,4个字节表示扩展平面。为了解决字符分隔,将基本平面的两段代码点保留,不表示任意字符。
110110xxxxxxxxxx(0xD800~0xD8FF)为高位代理,
110111xxxxxxxxxx(0xDC00~0xDFFF)为低位代理,
如果下两个字节以这俩开头,那么表示该字符是扩展平面的,需要读取4个字节,否则就是基本平面的,读取2个字节。
代码段 | 编码 |
0x000000~0x00FFFF | xxxxxxxx xxxxxxxx |
0x010000~0x10FFFF | 110110yy yyyyyyyy 110111xx xxxxxxxx |
UTF-32
UTF-32使用4个字节存储代码点,将代码点转为32位bit,位数不够左侧补0。
代码段 | 编码 |
0x000000~0x10FFFF | xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx |
字节序(ByteOrder Mark)
也叫大小端(BE,LE),超过2个字节就涉及到存储时,高字节放在高地址还是低地址的问题。如果高位字节在高地址,低位字节在低地址,那么称为小端,反之称为大端。
例如 0x1234,大端模式:
低地址-->高地址
0x12 0x34
小端模式:
低地址-->高地址
0x34 0x12
字节序一般放在文件的开始,标记高位在前还是低位在前。UTF-8可以没有字节序。字节序如下表
编码格式 | 字节序 |
UTF-8 | EF BB BF |
UTF-16 LE | FF FE |
UTF-16 BE | FE FF |
UTF-32 LE | FF FE 00 00 |
UTF-32 BE | 00 00 FE FF |