Windows程序员必须知道的字符编码和字符集

  1.  字符编码 (Character encoding)

在存储和传递文本过程中,为了使得所有电脑都能够正确的识别出文本内容,需要有一个统一的规则。

   2. 字符集 (Character Set) )

一般情况,一种编码方式对应一种字符集。如 ASCII,对应 ASCII 字符集。GBK 编码方式对应 GBK 字符集。但是也有一种编码方式,多种字符集的,Unicode 字符集有多种编码方式,如 utf-8,utf-16 等。

   3.  ASCII

ASCII(American Standard Code for Information Interchange,美国信息交换标准代码):使用 7 个 Bit 表示,共 128 个字符,刚好占用了一个字节中的后 7 位,共包括33 个控制字符和 95 个可显示字符。
.   4.  ANSI
ANSI (一种字符编码,此处不是表示美国国家标准学会的意思):ANSI 是为了让计算机支持更多的语言,而在 ASCII 的*础上的一种扩展字符编码。在不同语言操作上,ANSI 都表示当前计算机默认的编码方式。如在简体 Windows 操作下,ANSI 编码代表 GBK 编码;在繁体中文操作下,ANSI 编码代表 Big5 编码;在日文 Windows 操作系统中,ANSI 编码代表 Shift_JIS 编码;在英文操作系统下,ANSI 就是 ASCII 编码。
.   5.  MBCS
MBCS(Multi-Byte Character Set),早在 1980 年,中国就提出了使用 GB2312 编码方式来描述汉字。后来其他东亚国家也利用这种方式扩展 ASCII 编码字符集。台湾地区 5 大
企业推出的繁体 Big5 码,香港新加坡等后来也利用。日本韩国也相应推出了自己的编码方式。其实在这里,BIG5 既是编码方式,也是字符集。
  6.  GB2312(Guo Biao  2312) )
用双字节表示汉字,但是为了完全兼容 ASCII。汉字区“高字节”范围为 0xB0-0xF7,汉字区“低字节”范围 0xA1-0xFE,占用的码位 72*94=6768 个。
.   7.  GBK(Guo Biao Kuozhan)
后来发现 GB2312 的字符依然不够用,尤其是像“*”(***)字打不出来。然后决定汉字区的低字节完全不兼容 ASCII,只要当前字符属于汉字码,那么其后的字符也属于汉字码。这样在兼容 GB2312 的*础上,再添加了近两万字和字符(兼容繁体、日本汉字、韩国汉字等)。GBK 同样也是一种编码方式和字符集两种意义合于一体。
.   8.  GB18030
有两版 GB18030-2000 和 GB18030-2005,是 GBK 的扩展版,并且完全兼容 GBK。GB18030和 utf-8 类似,是动态的,既有单字节字体,也有双字节字节(BGK),也有三字节,四字节字符。Windows 默认支持的是 GBK,若要支持 GB18030,需要下载安装单独的支持包。
.  9.  Big5 5
1984 年台湾五家公司联合创立,称大五码,英文 Big5。Big5 也是双字节编码方式,收录了一万多字符,但是没有包含中文简体。Big5 目前也被香港、新家坡等地区国家使用。Big5 保存的文本,在简体操作系统下显示乱码,但是有些编辑器会自动识别,然后将其按 GBK 繁体字显示,即可正常显示。如 Notepad++即有此功能。
  10.  全角
GBK 用两个字节重新表示了一遍在 ASCII 中出现的字符,这些字符被叫全角字符。
  11.  半角
出现在 ASCII 中的字符,被称作半角字符。
  12. e Unicode  字符集
Unicode 字符集是 1990 年提出的,能够表示全世界所有国家的所有字符。但是支持Unicode 字符集的编码方式都有多种,如 UTF-8,UTF-16 等。编码方式虽然不同,但是
都是可以完整表示所有 Unicode 字符的。VS 里默认的 Unicode 字符集是指 utf-16 编码的,即固定双字节为一个字符。
  13.  UTF- -8 8
因为 Unicode 能够包含全球所有的字符,而 utf-8 又是其中比较节省字符存储的一种实现方式。所以现在的网站,*本都是以 utf-8 编码方式来存储、传输和显示了。UTF-8
是变字节长度的,用 1-6 个字节表示字符。用一个字符表示常见字符,用二个字节表示拉丁文、希腊文、西里尔字母、亚美尼亚语、希伯来文、阿拉伯文、叙利亚等,用三字
符表示常见汉字等,四个字节的字符比较少见。UTF-8 既能很方便存储英文,又能兼容全世界的字符,所以非常流行。
  14.  UTF- -8 8  解析算法
如果字节的第一位为 0,则 B 为 ASCII 码,并且 Byte 独立的表示一个字符;
如果字节的第一位为 1,第二位为 0,则 Byte 为一个非 ASCII 字符(该字符由多个字节表示)中的一个字节,并且不为字符的第一个字节编码;
如果字节的前两位为 1,第三位为 0,则 Byte 为一个非 ASCII 字符(该字符由多个字节
表示)中的第一个字节,并且该字符由两个字节表示;
如果字节的前三位为 1,第四位为 0,则 Byte 为一个非 ASCII 字符(该字符由多个字节表示)中的第一个字节,并且该字符由三个字节表示;
如果字节的前四位为 1,第五位为 0,则 Byte 为一个非 ASCII 字符(该字符由多个字节
表示)中的第一个字节,并且该字符由四个字节表示代码页(CodePag):代码页是字符集的数字值,不同的语言使用不同的代码页。例 如,ANSI
代码页为 1252,日文代码页为 932,简体中文(GBK)代码页为 936,繁体中文(Big5)代码页为 950。
  15.  语言包
系统默认的是 ANSI,但是同时也兼容 Unicode,这也是 Windows 的 API 有两套。当系统识别到当前字符是 Unicode 时,会以对应的 Unicode 编码方式去解码,Windows 支持的是 utf-8。解码之后,需要正确地显示出相应的字形,这个时候就需要语言包。如果没有语言包,会出现乱码。英文操作下,东亚语言归为一类,需要单独安装,安装时提示230MB。因为语言包比较大,所以在英文操作系统下,默认没有安装东亚语言包的,即不能正确显示 Unicode 下的东亚文字。至于语言包为什么这么大,猜测语言包必须得描述这个字体是如何点钩撇捺的等等。Windows 可以在控制面板中设置非 Unicode 程序显示语言。
  16.  大小端模式
由于 CPU 的缘故,存取数据分大端模式和小端模式,然后一些操作系统了软件也会有这样的区分。大端模式(Big-endian),是指数据的高字节,保存在内存的低地址中,而
数据的低字节,保存在内存的高地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加,而数据从高位往低位放。小端模式(Little-endian),
是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中,这种存储模式将地址的高低和数据位权有效地结合起来,高地址部分权值高,低地址部分
权值低,和我们的逻辑方法一致。
  17.  BOM(Byte Order Mark, 字节顺序标记) )
有一些文本编辑工具支持 UTF-8(BOM),字符 U+FEFF 如果出现在字节流的开头,则用来标识该字节流的字节序,是高位在前还是低位在前。接收者收到 FEFF,就表明这个字节
流是 Big-Endian 的;如果收到 FFFE,就表明这个字节流是 Little- Endian 的。Windows 文本默认的 Unicode 为大端 utf-16 存储,即以 FFFE 开头。BOM 主要应用Windows 下,而在某些系统下可能会出错,如 PHP 中容易读错。

 

编码  以此标记 (十六进制)  以此标记 (十进制)
UTF-8 EF BB BF 239 187 191
UTF-16(大端序) FE FF 254 255
UTF-16(小端序) FF FE 255 254
UTF-32(大端序) 00 00 FE FF 0 0 254 255
UTF-32(小端序) FF FE 00 00  255 254 0 0 

 

  18.  GBK 、e Unicode 他 他  UTF- -8 8  转换
UTF-8 和 GBK 同属于多字节 MultiByte,Unicode 默认是 UTF-16,即宽字符,两个字节。

GBK(ANSI)->Unicode->UTF-8,反向即 UTF-8->Unicode->GBK(ANSI)。

 

  1. [cpp] view plain copy
     
     print?在CODE上查看代码片派生到我的代码片
    1. // 注释:多字节包括GBK和UTF-8    
    2. int GBK2UTF8(char *szGbk,char *szUtf8,int Len)    
    3. {    
    4.     // 先将多字节GBK(CP_ACP或ANSI)转换成宽字符UTF-16    
    5.     // 得到转换后,所需要的内存字符数    
    6.     int n = MultiByteToWideChar(CP_ACP,0,szGbk,-1,NULL,0);    
    7.     // 字符数乘以 sizeof(WCHAR) 得到字节数    
    8.     WCHAR *str1 = new WCHAR[sizeof(WCHAR) * n];    
    9.     // 转换    
    10.     MultiByteToWideChar(CP_ACP,  // MultiByte的代码页Code Page    
    11.         0,            //附加标志,与音标有关    
    12.         szGbk,        // 输入的GBK字符串    
    13.         -1,           // 输入字符串长度,-1表示由函数内部计算    
    14.         str1,         // 输出    
    15.         n             // 输出所需分配的内存    
    16.         );    
    17.     
    18.     // 再将宽字符(UTF-16)转换多字节(UTF-8)    
    19.     n = WideCharToMultiByte(CP_UTF8, 0, str1, -1, NULL, 0, NULL, NULL);    
    20.     if (n > Len)    
    21.     {    
    22.         delete[]str1;    
    23.         return -1;    
    24.     }    
    25.     WideCharToMultiByte(CP_UTF8, 0, str1, -1, szUtf8, n, NULL, NULL);    
    26.     delete[]str1;    
    27.     str1 = NULL;    
    28.     
    29.     return 0;    
    30. }  

    [cpp] view plain copy
     
     print?在CODE上查看代码片派生到我的代码片
    1. //UTF-8 GBK    
    2. int UTF82GBK(char *szUtf8,char *szGbk,int Len)    
    3. {    
    4.     int n = MultiByteToWideChar(CP_UTF8, 0, szUtf8, -1, NULL, 0);    
    5.     WCHAR * wszGBK = new WCHAR[sizeof(WCHAR) * n];    
    6.     memset(wszGBK, 0, sizeof(WCHAR) * n);    
    7.     MultiByteToWideChar(CP_UTF8, 0,szUtf8,-1, wszGBK, n);    
    8.     
    9.     n = WideCharToMultiByte(CP_ACP, 0, wszGBK, -1, NULL, 0, NULL, NULL);    
    10.     if (n > Len)    
    11.     {    
    12.         delete[]wszGBK;    
    13.         return -1;    
    14.     }    
    15.     
    16.     WideCharToMultiByte(CP_ACP,0, wszGBK, -1, szGbk, n, NULL, NULL);    
    17.     
    18.     delete[]wszGBK;    
    19.     wszGBK = NULL;    
    20.     
    21.     return 0;    
    22. }  

    19. 附ASCII码图表

 

posted @ 2017-02-15 22:29  飞鹤0755  阅读(5655)  评论(0编辑  收藏  举报