@saltyang
2019-02-18T17:59:49.000000Z
字数 4163
阅读 1251
字符集、编码
装载文章
美国信息交换标准代码,是计算机最早通用的编码方案。
- 这种编码占用7个Bit,在计算机中占用一个字节,8位,最高位没用,通讯的时候有时用作奇偶校验位。因此ASCII编码的取值范围实际上是:0x00-0x7f,只能表示128个字符。后来发现128个不太够用,做了扩展,叫做ASCII扩展编码,用足八位,取值范围变成:0x00-0xff,能表示256个字符。其实这种扩展意义不大,因为256个字符表示一些非拉丁文字远远不够,但是表示拉丁文字,又用不完。所以扩展的意义还是为了下面的ANSI编码服务。
美国国家标准协会,也就是说,每个国家(非拉丁语系国家)自己制定自己的文字的编码规则,并得到了ANSI认可,符合ANSI的标准,全世界在表示对应国家文字的时候都通用这种编码就叫 ANSI编码
- 中国的ANSI 编码和在日本的ANSI 的意思是不一样的,因为都代表自己国家的文字编码标准。比如中国的 ANSI 对应就是 GB2312 标准,日本就是 JIT 标准,香港,台湾对应的是 BIG5 标准等等。
- GBK 编码是微软从95开始搞的一个标准,GB2312 里面只有6763个汉字,682个符号,所以确实有时候不是很够用。GBK 一直能和 GB2312 相互混淆并且相安无事的一个重要原因是 GBK 全面兼容 GB2312,所以没有出现任何冲突,你用GB2312编码的文件通过 GBK 去解释一定能获得相同的显示效果,换句话说:GBK 对GB2312就是,你有的,我也有,你没得的,我还有!
ANSI的标准是什么呢?
首先是ASCII的代码你不能用!也就是说ASCII码在任何ANSI中应该都是相同的。其他的,你们自己扩展。所以呢,中国人就把ASCII码变成8位,0x7f之前我不动你的,我从0xa0开始编,0xa0到0xff才95个码位,对于中国字那简直是杯水车薪,因此,就用两个字节吧,因此编码范围就从0xA1A1 - 0xFEFE,这个范围可以表示23901个汉字。基本够用了吧,GB2312才7000多个呢!GBK更猛,编码范围是从0x8140 - 0xFEFE,可以表示3万多个汉字。可以看出,这两种方案,都能保证汉字头一个字节在0x7f以上,从而和ASCII不会发生冲突。能够实现英文和汉字同时显示。
BIG5,香港和台湾用的比较多,繁体,范围: 0xA140 - 0xF9FE, 0xA1A1 - 0xF9FE,每个字由两个字节组成,其第一字节编码范围为0xA1~0xF9,第二字节编码范围为0x40-0x7E与0xA1-0xFE,总计收入13868个字 (包括5401个常用字、7652 个次常用字、7个扩充字、以及808个各式符号)。
那么到底ANSI是多少位呢?
- GB2312、GBK、BIG5中,是2位!但是其他标准或者其他语言如果不够用,就完全可能不止两位!
- GB18030-2000(GBK2K)在GBK的基础上进一步扩展了汉字,增加了藏、蒙等少数民族的字形。GBK2K从根本上解决了字位不够,字形不足的问题。它有几个特点:它并没有确定所有的字形,只是规定了编码范围,留待以后扩充。 编码是变长的,其二字节部分与GBK兼容;四字节部分是扩充的字形、字位,其编码范围是首字节0x81-0xfe、二字节0x30-0x39、三字节0x81-0xfe、四字节0x30-0x39。它的推广是分阶段的,首先要求实现的是能够完全映射到Unicode3.0标准的所有字形。它是国家标准,是强制性的。
一个超大的字符集,它可以容纳全世界所有的文字字符,再对它们统一进行编码,让每一个字符都对应一个不同的编码值,从而就不会再有乱码了。
- Unicode编码范围是:0-0x10FFFF,
17 * 256 * 2256 = 1114112
可以容纳1114112个字符,100多万啊。全世界的字符根本用不完了,Unicode 5.0版本中,才用了238605个码位.因此从码位范围看,严格的Unicode需要3个字节来存储。但是考虑到理解性和计算机处理的方便性,理论上还是用4个字节来描述。- Unicode编码点分为17个平面(plane),每个平面包含256(即65536)个码位(code point)。17个平面的码位可表示为从U+xx0000到U+xxFFFF,其中xx表示十六进制值从0到16,共计17个平面。
- UTF-8/16, UCS-2/UCS-4是Unicode的编码方式,其中UTF-8是变长编码,UTF-16用2个字节和4个字节进行编码,UCS-2/UCS-4是固定编码方式,分别用2个字节/4个字节表示一个字符。
UTF-8的特点是对不同范围的字符使用不同长度的编码。对于0x00-0x7F之间的字符,UTF-8编码与ASCII编码完全相同。UTF-8编码的最大长度是4个字节。
UTF-16编码以16位无符号整数为单位。注意是16位为一个单位,不表示一个字符就只有16位。现在机器上的unicode编码一般指的就是UTF-16。绝大部分2个字节就够了,但是不能绝对的说所有字符都是2个字节。这个要看字符的unicode编码处于什么范围而定,有可能是2个字节,也可能是4个字节。这点请注意!
- 通常说的Unicode就是指UTF-16。
- 多字节字符系统或者字符集,基于ANSI编码的原理上,对一个字符的表示实际上无法确定他需要占用几个字节的,只能从编码本身来区分和解释。因此计算机在存储的时候,就是采用多字节存储的形式。也就是你需要几个字节我给你放几个字节,比如A我给你放一个字节,比如”中“,我就给你放两个字节,这样的字符表示形式就是MBCS。在基于GBK的windows中,不会超过2个字节,所以windows这种表示形式有叫做DBCS(Double-Byte Chactacter System),其实算是MBCS的一个特例。
- C语言默认存放字符串就是用的MBCS格式。从原理上来说,这样是非常经济的一种方式。
MBCS, UNICODE, UTF-8之间的转换C++实现
- 一个系统在处理文字的时候,必须要告诉计算机你的ANSI是哪个国家和地区的标准,这种国家和标准的代号(其实就是字符编码格式的代号),微软称为Codepage代码页,其实这个代码页和字符集编码的意思是一样的。告诉你代码页,本质就是告诉了你编码格式。
- GBK的在微软的代码页是936,告诉你代码页是936其实和告诉你我编码格式是GBK效果完全相同。那么处理文本的时候就不会有问题,不会去考虑某个代码是显示的韩文还是中文,同样,日文和韩文的代码页就和中文不同,这样就可以避免编码冲突导致计算机不知如何处理的问题。当然用这个也可以很容易的切换语言版本。
字节序,具体来说,就是多字节数据(大于一个字节的数据)在计算机中存储、读取时其各个字节的排列顺序。
- LE(little endian):小字节字节序,意思就是一个单元在计算机中的存放时按照低位在前(低地址),高位在后(高地址)的模式存放。
- BE(big endian):大字节字节序,和LE相反,是高位在前,低位在后。
- 比如一个unicode编码为:0x006C49,如果是LE,那么在文件中的存放顺序应该是:49 6c 00如果是BE ,那么顺序应该是:00 6c 49
到底采用什么编码,如果能检测就好了。专家们也是这么想的,所以专家给每种格式和字节序规定了一些特殊的编码,这些编码在unicode 中是没有使用的,所以不用担心会冲突。
- BOM(Byte Order Mark)头。意思是字节序标志头。通过它基本能确定编码格式和字节序。
UTF编码 ║ Byte Order Mark
UTF-8 ║ EF BB BF
UTF-16LE ║ FF FE
UTF-16BE ║ FE FF
UTF-32LE ║ FF FE 00 00
UTF-32BE ║ 00 00 FE FF
所以通过检测文件前面的BOM头,基本能确定编码格式和字节序。
但是这个BOM头只是建议添加,不是强制的,所以不少软件和系统没有添加这个BOM头(所以有些软件格式中有带BOM头和NoBOM头的选择),这个时候要检测什么格式,就比较麻烦了当然可以检测,但是不能保证100%准确,只能通过编码范围从概率上来检查,虽然准确度还是比较高,但是不能保证100%。所以,时常看到检测错误的软件,也不奇怪了。
- Windows定义设置的Unicode数据类型有哪些?
数据类型 说明
WCHAR Unicode字符
PWSTR 指向Unicode字符串的指针
PCWSTR 指向1个恒定的Unicode字符串的指针
对应的ANSI数据类型分别为:CHAR、LPSTR、LPCSTR。
ANSI/Unicode通用数据类型为TCHAR、PTSTR、LPCTSTR。
- 如何对Unicode进行操作?
字符集 特性 实例
ANSI 操作函数function以str开头 strcpy
Unicode 操作函数function以wcs开头 wcscpy
MBCS 操作函数function以_mbs开头 _mbscpy
ANSI/Unicode 操作函数function以_tcs开头 _tcscpy(C运行期库)
ANSI/Unicode 操作函数function以lstr开头 lstrcpy(Windows函数function)
- 如何表示Unicode字符串常量?
字符集 实例
ANSI“string”
UnicodeL“string”
ANSI/UnicodeT(“string”)或_TEXT(“string”)