ANSI / SBCS / DBCS / MBCS / ASCII / EUC / EUC-CN / GB2312 / GBK / GB18030 / BIG5
ANSI: American National Standards Institute 美国国家标准学会,由这个标准学会制订的一种编码规则。 • 采用多字节系统 (MBCS) 的变长编码,每个字符可以是单个字节、双字节,也可以是多字节的; • 兼容单字节字符集 (SBCS) 和双字节字符集 (DBCS); • 兼容 EUC/EUC-CN 双字节编码。由于兼容了这个编码,那么 ANSI 的双字节编码也是大端存储 (Big Endian) 的了; • 不同的国家和地区可以使用不同的编码规则,这些编码对应到这些国家和地区的代码页 (Code Page) 上。
SBCS: Single Byte Character Set 单字节字符集。 • 每个字符都是 1 个字节的编码,ASCII 是 1 个字节的编码,很多欧洲语言 1 个字节的编码也足够了。 • ANSI 兼容了 SBCS,每个国家和地区的编码可能都不同,对应到这些国家和地区的代码页 (Code Page) 上。
DBCS: Double-Byte Character Set 双字节字符集。 • 每个字符是 1 个或 2 个字节的编码,规则请参考后面的 “字节类型” 里面的描述。 • ANSI 兼容了 DBCS,每个国家和地区的编码可能都不同,对应到这些国家和地区的代码页 (Code Page) 上。
MBCS: Multi-Byte Chactacter Set (System) 多字节字符集。 • 每个字符采用 1 个或多个字节的编码,规则请参考后面的 “字节类型” 里面的描述。 • ANSI 兼容了 MBCS,每个国家和地区的编码可能都不同,对应到这些国家和地区的代码页 (Code Page) 上。
Byte Type:字节类型,DBCS/MBCS 双字节/多字节系统,每个字符的字节数不同,为了区分哪些字节是组合在一起的,哪些是单个字节的字符
首先看 DBCS 双字节字符集的编码规则: • Single Byte: 单字节字符,编码范围 0x00 ~ 0x7F; • Lead Byte: 双字节字符的第一个字节,范围 0x80 ~ 0xFF,遇到这样的字符,认后面还有一个和它组合在一起的字符; • Trail Byte: 双字节字符的第二个字符,范围 0x01 ~ 0xFF,因为只要找了 Lead Byte,跟在它后面的就是 Trail Byte,所以 Trail Byte 可以使用任何编码值不等于 0 的字符。
然后看 MBCS 多字节字符集的编码规则: • 在 DBCS 的基础上,兼容 DBCS,是 DBCS 的升级版本; • 超出 DBCS 编码的范围了,需要用 4 个字节的编码的时候,用 2 个标准的 DBCS 的双字节字符表示 4 个字节的字符。所以,4 个字节的字符的字节类型依次为 Lead Byte, Trail Byte, Lead Byte, Trail Byte。 • 根据什么判断 MBCS 字符到底是 2 字节还 4 字节呢?只有看编码范围了。
比如 GB18030 编码,就是 MBCS 多字节系统,GB18030 利用 Trail Byte 的值区分双字节字符和四字节字符: GB18030 规定 Lead Byte 的范围是 0x81 ~ 0xFE,Trail Byte 的范围是 0×30 ~ 0×39, 0×40 ~ 0×7E, 0×80 ~ 0×FE。 • Trail Byte 范围 0×40 ~ 0×7E 或 0×80 ~ 0×FE,这样的字符,是双字节字符。 • Trail Byte 范围 0×30 ~ 0×39,那么这个字符就是 4 个字节的字符。 例如:0x81, 0x40 是双字节的,0x81, 0x30 就是 4 个字节的,前面或后面还有一个双字节字符和它组合在一起。
请参考 GB18030 编码测试程序 查看和进一步了解 Byte Type 和 MBCS / GB18030 的编码规则。
ASCII: American Standard Code for Information Interchange,美国信息交换标准代码。 • ASCII 读音为 /ˈæski/ 或 ass-kee, 因为后面的 II 是 Information Interchange 的缩写,不是罗马数字 “Ⅱ”,所以读为 “阿斯克”,而不能读作 “阿斯克二”。 • 只有 7 位的二进制编码,范围从 0 ~ 127,一共 128 个字符,包含英文字母、数字、标点符号和一些控制符。 • 所谓的 “两个 ASCII 表示一个汉字” 是属于 ANSI 编码,这里的 ASCII 是不能表示汉字的。
EASCII: Extended ASCII,延伸美国标准信息交换码 • 在 ASCII 的基础上,从 7 位二进制编码扩充到 8 位二进制码,范围 0 ~ 255,一共 256 个字符。 • 对应于代码页 Code Page 437,所以又称为 CP 437,OEM 437,DOS-USA 或 MS-DOS Latin US。 • 所谓的 “两个 ASCII 表示一个汉字” 是属于 ANSI 编码,这里的 ASCII 是不能表示汉字的,汉字的代码页是 936 或 950,而不是 437。
GB2312: 中国大陆和新加坡使用的一种早期的汉字编码,标准编号为 GB2312-1980,是中国国家标准总局 1980 年发布的信息交换用汉字编码字符集,收录了 6763 个汉字,682 个全角字符。其中一级汉字 3755 个,二级汉字 3008 个,全角字符包括拉丁字母、希腊字母、日文平假名及片假名字母、俄语西里尔字母等。
区位码:GB2312 采用分区的方式编码: • 01~09 区为符号和特殊字符, • 10~15 区未使用, • 16~55 区为一级汉字,有 3755 个最常用的汉字,按照汉语拼音的顺序排列, • 56~87 区为二级汉字,有 3008 个次常用的汉字,按照部首及笔画顺序排列, • 88~94 区未使用, 这些汉字或符号的编码,第几区的数值为 “区码”,这个字是这个区的第几个字,为 “位码”,例如 “啊” 的 GB2312 的第一个汉字,是第 16 区的第 01 个字,它的区位码就是 1601。
EUC 编码:这是早期的双字节编码方式,在 ANSI 之前,大家都遵照这个标准 EUC (Extended Unix Code) 是一个使用 8 位编码来表示字符的方法。 EUC 规定单字节编码范围 0x00 ~ 0x7F,双字节编码采用两个 0x80 ~ 0xFF 的字节,对应于区位码上, “区码” 加上一个数值,范围调整在 0x80 ~ 0xFF 之内,称为 “区字节”,是编码的高位字节, “位码” 加上一个数值,范围调整在 0x80 ~ 0xFF 之内,称为 “位字节”,是编码的低位字节, 由此可见,EUC 是一个大端存储 (Big Endian) 的编码方式。
EUC-CN 是中国的 EUC 编码,即 GB2312 编码。 区字节 = 区码 + 0xA0,为编码的高位字节,EUC 是 Big Endian 的,区字节储存在电脑里面要放在前面, 位字节 = 位码 + 0xA0,为编码的低位字节,EUC 是 Big Endian 的,位字节储存在电脑里面要放在后面。
国标码,汉字机内码 (汉字内码) • 机内码:EUC-CN 的区字节和位字节组合在一起,就是 GB2312 的机内码 (汉字内码),区字节为高位字节,位字节为低位字节。 • 国标码:机内码的高位字节和低位字节,都把最高位清零,低 7 位不变,即 “国标码 = 机内码 – 0x8080”。
最终存储在电脑里存储器面的编码值:以上让人头晕眼花的描述中的 GB2312,或者说 EUC-CN 的所有的 “码” 中,只有汉字机内码是储存在电脑里面的格式,是他们的最终编码,通常都是用十六进制表示的。
GB2312 编码与 ANSI 的对应: • 对应于代码页 Code Page 20936 (大陆及新加坡的代码页为 CP 936,即 GBK 编码,很少有人使用 CP 20936)。 • Lead Byte = 区字节,由于 ANSI 要兼容 EUC,那么就要采用大端存储 (Big Endian),把高位字节放在前面; • Trail Byte = 位字节,由于 ANSI 要兼容 EUC,那么就要采用大端存储 (Big Endian),把低位字节放在后面。
例如,依然是采用字符编码的例子当中的一个 ANSI 编码字符的例子: 这个是 ANSI 版本的编译器,例如 C++ Builder 编译器在 Windows 环境下 ANSI 版本的项目编译运行的结果。 如果你的编译器不支持,请看下一个例子————GB2312 字符串的例子。
#include <stdio.h>
int _tmain(int argc, _TCHAR* argv[]) { unsigned short c = ‘我’ ; // 内码 = 字符本身的值 (CP936 代码页 ANSI 编码的值) unsigned short gb = c & 0x7F7F ; // 国标码 = 内码两个字节高位都清零 unsigned char qz = c >> 8 ; // 区字节 = 内码高位字节 unsigned char wz = c & 0x00FF ; // 位字节 = 内码低位字节 unsigned char qm = qz – 0xA0 ; // 区码 = 区字节 – 0xA0 unsigned char wm = wz – 0xA0 ; // 位码 = 位字节 – 0xA0 unsigned short qw = qm*100 + wm; // 区位码是十进制的,要用十进制计算 unsigned char lb = qz ; // Lead Byte = 区字节,因为是大端存储 (Big Endian) unsigned char tb = wz ; // Trail Byte = 位字节,因为是大端存储 (Big Endian) printf(“‘我’ 的机内码 = %04X\n” , c ); printf(“‘我’ 的国标码 = %04X\n” , gb ); printf(“‘我’ 的区字节 = 0x%02X\n” , qz ); printf(“‘我’ 的位字节 = 0x%02X\n” , wz ); printf(“‘我’ 的区码 = %02d\n” , qm ); printf(“‘我’ 的位码 = %02d\n” , wm ); printf(“‘我’ 的区位码 = %04d\n” , qw ); printf(“‘我’ 的 Lead Byte = 0x%02X\n” , lb ); printf(“‘我’ 的 Trail Byte = 0x%02X\n” , tb ); char s[] = { lb, tb, 0 }; // 储存在字符串前面的是 Lead Byte,后面的是 Trail Byte printf(“由 Lead Byte 和 Trail Byte 合成字符串 = \”%s\”\n”, s); // 输出字符串 printf(“\n请按回车键退出…”); getchar(); return 0; } | 运行结果:
汉字 ‘我’ 的 |
值 |
说明 |
机内码 |
CED2 |
单个字符,得到 ‘我’ 的字符编码,即汉字机内码 (汉字内码),整数值为 c = 0xCED2 (十进制的 52946)。 |
国标码 |
4E52 |
把汉字内码两个字节 0xCE 和 0xD2 的高位清零,得到 0x4E, 0x52,也可以用 0xCED2 – 0x8080 = 0x4E52 |
区字节 |
0xCE |
‘我’ 的区字节为高位字节 0xCE,即 ANSI 的 Lead Byte |
位字节 |
0xD2 |
‘我’ 的位字节为低位字节 0xD2,即 ANSI 的 Trail Byte |
区码 |
46 |
‘我’ 的区码是 46 即区字节 0xCE – 0xA0 = 0x2E (0x2E 等于十进制的 46), |
位码 |
50 |
‘我’ 的位码是 50,即位字节 0xD2 – 0xA0 = 0x32 (0x32 等于十进制的 50), |
区位码 |
4650 |
‘我’ 的区位码是 4650,是根据前面两条,区码和位码合在一起得到的结论。 |
Lead Byte |
0xCE |
在电脑存储器里面储存的字符串,在前面的是 Lead Byte,由于是大端存储 (Big Endian),是区字节 0xCE |
Trail Byte |
0xD2 |
在电脑存储器里面储存的字符串,在后面的是 Trail Byte,由于是大端存储 (Big Endian),是位字节 0xD2 |
注:在中国大陆简体中文的电脑里面得到的是 GB2312 编码,在中国港台地区得到的是 BIG5 码,他们的概念相同,但是编码值不同。
再继续写一个例子————GB2312 字符串的例子: 如果你的编译器不支持前面的 ANSI 字符的例子,可以用这个例子。 这个例子是在 C++ Builder 编译器里面 Windows 系统 ANSI 编码版本的项目运行通过的,也可以兼容 DOS/EUC-CN 环境。
#include <stdio.h>
int _tmain(int argc, _TCHAR* argv[]) { char s[] = “我”; unsigned char lb = s[0] ; // ANSI: 储存在字符串前面的是 Lead Byte unsigned char tb = s[1] ; // ANSI: 储存在字符串后面的是 Trail Byte unsigned char qz = lb ; // 区字节 = Lead Byte,因为是大端存储 (Big Endian) unsigned char wz = tb ; // 位字节 = Trail Byte,因为是大端存储 (Big Endian) unsigned short nm = (qz<<8)|wz ; // 内码 = 区字节是高位字节,位字节是低位字节 unsigned short gb = nm & 0x7F7F ; // 国标码 = 内码两个字节高位都清零 unsigned char qm = qz – 0xA0 ; // 区码 = 区字节 – 0xA0 unsigned char wm = wz – 0xA0 ; // 位码 = 位字节 – 0xA0 unsigned short qw = qm*100 + wm ; // 区位码是十进制的,要用十进制计算 printf(“原始字符串 = \”%s\”\n” , s ); printf(“‘我’ 的 Lead Byte = 0x%02X\n” , lb ); printf(“‘我’ 的 Trail Byte = 0x%02X\n” , tb ); printf(“‘我’ 的区字节 = 0x%02X\n” , qz ); printf(“‘我’ 的位字节 = 0x%02X\n” , wz ); printf(“‘我’ 的机内码 = %04X\n” , nm ); printf(“‘我’ 的国标码 = %04X\n” , gb ); printf(“‘我’ 的区码 = %02d\n” , qm ); printf(“‘我’ 的位码 = %02d\n” , wm ); printf(“‘我’ 的区位码 = %04d\n” , qw ); printf(“\n请按回车键退出…”); getchar(); return 0; } | 运行的结果:
汉字 ‘我’ 的 |
值 |
说明 |
Lead Byte |
0xCE |
在电脑存储器里面储存的字符串,在前面的是 Lead Byte,由于是大端存储 (Big Endian),是区字节 0xCE |
Trail Byte |
0xD2 |
在电脑存储器里面储存的字符串,在后面的是 Trail Byte,由于是大端存储 (Big Endian),是位字节 0xD2 |
区字节 |
0xCE |
‘我’ 的区字节为高位字节 0xCE,即 ANSI 的 Lead Byte |
位字节 |
0xD2 |
‘我’ 的位字节为低位字节 0xD2,即 ANSI 的 Trail Byte |
机内码 |
CED2 |
区字节和位字节合在一起就是机内码,区字节是高位字节,位字节是低位字节。 |
国标码 |
4E52 |
把汉字内码两个字节 0xCE 和 0xD2 的高位清零,得到 0x4E, 0x52,也可以用 0xCED2 – 0x8080 = 0x4E52 |
区码 |
46 |
‘我’ 的区码是 46 即区字节 0xCE – 0xA0 = 0x2E (0x2E 等于十进制的 46), |
位码 |
50 |
‘我’ 的位码是 50,即位字节 0xD2 – 0xA0 = 0x32 (0x32 等于十进制的 50), |
区位码 |
4650 |
‘我’ 的区位码是 4650,是根据前面两条,区码和位码合在一起得到的结论。 |
注:在中国大陆简体中文的电脑里面得到的是 GB2312 编码,在中国港台地区得到的是 BIG5 码,他们的概念相同,但是编码值不同。
GBK: 国标扩展码,是中国大陆 1995 年制定的编码标准,这是一个过渡版本的标准,正式版本为 GB13000。 • 在 GB2312 的基础上,扩充了编码范围,和 GB2312 完全兼容: • 区字节范围:0x81 ~ 0xFE,对应于 ANSI 版本的 Lead Byte, • 位字节范围:0x40 ~ 0x7E 和 0x80 ~ 0xFE 两段,中间不包含 0x7F 这个值,对应于 ANSI 版本的 Trail Byte。 • 一共 23940 个码位,收录了 21003 个汉字,包括 GB2312 全部汉字、BIG5 编码的所有汉字和新增加的汉字。 • 对应于 ANSI 代码页 Code Page 936,简称 CP 936。 • 和 GB13000 的区别: 同一套文字的两种不同编码,GB13000-1993 采用 UCS2 编码,GB13000-2010 采用 UTF-16 编码,详见 UNICODE 章节。
虽说 GBK 为国家标准的过渡标准,正式标准为 GB13000-1993 和 GB13000-2010,但是到现在为止,大家还在折腾 CP 936 代码页的 GBK 编码的 ANSI 版本的程序呢。
大家都不遵照 GB13000 标准写程序,这个不愿大家,要愿就愿微软公司。GB13000 在 1993 年就制定了,在这个标准之后出版的 Windows 95 是 ANSI 编码的,CP 936 代码页映射在了 GBK 编码上,不支持 UNICODE,也不支持 GB13000。这样的系统一直持续到 Windows 2000 出版之前。
虽说 Windows 2000 开始,操作系统的内核改成了 UTF-16 编码,兼容 GB13000 了,可是微软又把 ANSI 留下来了,CP 936 代码页的 GBK 编码仍然能用,老程序员写程序习惯了就不愿意改了,新程序员学习的老程序员的经验,书和资料也更新的不及时,所以新程序员也不愿意改用新标准。
本文作者 — Victor Chen 建议大家再创建新的项目采用 UNICODE 编码版本的程序,这样不仅仅是和新的国家标准兼容,而且还实现了国际化。
GB18030: 目前中国大陆最新的 MBCS 字符编码标准。GB18030 是在 GBK 的基础上进行了扩充。 • GB18030-2000,是 2000 年发布的, • GB18030-2005,是 2005 年发布的,目前正在使用的标准, • GB18030 的代码页为 CP 54936。 • GB18030-2005 兼容 GBK/GB2312,收录了 70244 个汉字,包含了 GBK、GB2312、GB13000 的汉字和扩充的汉字,还收录了藏文、蒙文、维吾尔文等主要的少数民族文字。 • 2000 年发布的 GB18030-2000 取代了 GBK,并且要求 PC 平台所有的软件都必须强制支持 GB18030,嵌入式平台没有强制要求。 • 编码方式参考 ANSI 的 Byte Type (字节类型),分为单字节字符、双字节字符和四字节字符,即每个字符 1, 2 或 4 个字节。
对于这个编码,本文作者 — Victor Chen 又有话要说了: • 对于强制执行,大家常用的软件当中,从来没发现有支持 GB18030 的 ANSI / MBCS 版本的软件,也没发现有任何程序员希望自己的程序支持 GB18030,虽说理论上肯定有这样的软件。现在的 ANSI / MBCS 版本的软件,包括刚刚出版的新版软件,甚至还有不支持 GBK 的,仅仅支持 GB2312。 • UNICODE 版本的软件,按理说就不是 GB18030 这样的 ANSI 系列或 MBCS 系列的编码了,如果程序员没有 “自作聪明” 的自己去玩处理 UNICODE 编码,肯定会支持 GB18030 所有的字符的,因为 UNICODE 已经涵盖了 GB18030 所有的字符。 • 自作聪明的程序员太多了,我遇到了无数多个,包括现实生活中的、论坛里面的、IM 聊天软件里面的,他们自己处理了 UNICODE 编码值,把汉字限制在 U+4E00 ~ U+9FBF 这个基础的 CJK 编码范围,也许是为了偷懒,这太糟糕了,甚至无法涵盖 GBK 的范围,更别说 GB18030 了。
GB18030 编码的字节类型,字符个数和字节数 – 判断字符串里面的字符是双字节字符或是单字节字符,还有四字节字符的判断 【例:多字节字符集 (MBCS) 的例子 – GB18030 编码的例子】
GB18030 测试程序: • 这个测试程序很无聊?其实不然,因为在很久以前国家标准就规定了,要强制执行 GB18030 标准,那么无论如何也要了解一下。
void __fastcall TForm1::Button1Click(TObject *Sender) { UnicodeString utf16 = L”𠀾”; // 这是一个 UTF-16 字符串
UTF8String utf8 = utf16; // 转为 UTF-8 字符串: UTF8String AnsiString ansi = utf16; // 转为 ANSI 字符串: AnsiString AnsiStringT<936> gbk = utf16; // 转为 GBK 编码的字符串 AnsiStringT<54936> gb18030 = utf16; // 转为 GB18030 编码的字符串
char *pstr = gb18030.c_str(); // pstr 指针指向 GB18030 编码的字符串
Memo1->Lines->Add(String(L”UTF-16 字符串: \””) + utf16 + L”\””); Memo1->Lines->Add(String(L”UTF-8 字符串: \””) + utf8 + L”\””); Memo1->Lines->Add(String(L”ANSI 字符串: \””) + ansi + L”\””); Memo1->Lines->Add(String(L”GBK 字符串: \””) + gbk + L”\””); Memo1->Lines->Add(String(L”GB18030 字符串: \””) + gb18030 + L”\””); Memo1->Lines->Add(String(L”指向 GB18030 的 char *: \””) + pstr + L”\””);
UnicodeString s;
s = L””; for(int i=0; pstr[i]; i++) { if(!s.IsEmpty()) s += L”, “; s.cat_sprintf(L”0x%02X”, (int)(unsigned char)pstr[i]); } Memo1->Lines->Add(L”GB18030 编码: ” + s);
s = L””; for(int i=1; i<=utf8.Length(); i++) { if(!s.IsEmpty()) s += L”, “; s.cat_sprintf(L”0x%02X”, (int)(unsigned char)utf8[i]); } Memo1->Lines->Add(L”UTF-8 编码: ” + s);
s = L””; for(int i=1; i<=utf16.Length(); i++) { if(!s.IsEmpty()) s += L”, “; s.cat_sprintf(L”0x%04X”, utf16[i]); } Memo1->Lines->Add(L”UTF-16 编码: ” + s);
UCS4String utf32 = UnicodeStringToUCS4String(utf16); s = L””; for(int i=0; utf32[i]; i++) { if(!s.IsEmpty()) s += L”, “; s.cat_sprintf(L”0x%X”, utf32[i]); } Memo1->Lines->Add(L”UTF-32 编码: ” + s);
s.sprintf(L”U+%X”, utf32[0]); Memo1->Lines->Add(L”UNICODE 编码: ” + s); } | 运行结果:
从这个程序的运行结果来看: • 常用的 UnicodeString、UTF8String 显示正常, • 常用的 AnsiString 和 char * 显示失败,变成了俩问号 “??”,因为他们是系统默认的代码页 CP 936,对应的是 GBK 编码, • AnsiStringT<936> 指定了代码页为 936,那么就是 GBK 编码了,“𠀾” 这个字不在 GBK 编码之内,所以无法转换成功和显示, • AnsiStringT<54936> 指定了代码页为 54936,那么就是 GB18030 编码了,转换编码成功,并且正常显示出来了, • char *pstr 指向的是 GB18030 编码的字符串,但是无法直接显示出来,因为系统认为 char * 是默认的 CP 936 代码页 GBK 编码, • 通过 pstr 显示出来的 GB18030 的编码值是正确的,0x95, 0x32, 0x88, 0x38,通过 Byte Type 章节,可以知道: 0x95 和 0x88 是 Lead Byte,0x32 和 0x38 是 Trail Byte,他们符合 DBCS 的编码规则,同时也符合 MBCS 的规则; • UNICODE 系列编码:UTF-8, UTF-16 的显示结果和编码值都是正确的,UTF-32 或 UCS4 只能用来转码,不能参与运算和显示, 这是因为 Windows 内核是 UTF-16 编码的,并不支持 UTF-32 和 UCS4,编译器也没有做,也认为没有必要做他们的显示和运算, • GB18030 编码,只有定义为 AnsiStringT<54936> 类型,才能正常显示和参与运算,char * 只能做运算,无法直接显示。
测试程序的结论: • 程序里面所有的字符都采用 AnsiStringT<54936> 很麻烦, 其次 GB18030 编码,包括 MBCS 的弱点,很难处理两个双字节拼成的四字节字符的 “半个汉字” 问题,因为这两半的编码没有任何区别, • 通过 UNICODE 支持,非常简单: 只要不输出到文件,或者透过通讯传输数据,根本就不知道程序内部是什么编码的, 如果非得要 GB18030 编码的文件,存盘的时候给他转个编码,只要给 AnsiStringT<54936> 类型的字符串赋值再保存就可以了。
BIG5: 台湾、香港和澳门地区最常用的编码,共收录 13,060 个汉字。 • BIG5 为 DBCS 双字节字符集,对应于代码页 Code Page 950。 • 编码为大端存储 (Big Endian) ,Lead Byte 的范围:0x81 ~ 0xFE,Trail Byte 的范围:0x40-0x7E, 0xA1-0xFE。 • 如果一个汉字的简体字和繁体字写法不同,那么这个汉字只收录了繁体字,没有收录简体字,所以简体中文的文字,需要把简繁写法不同的字转成繁体,才能转为 BIG5 码,否则这些字会丢失。 • 把 BIG5 编码的文字转为 GBK,可以只进行编码转换,不用简繁体转换也不会丢失文字,因为 GBK 已经包含了 BIG5 里面的繁体字。
代码页 (Code Page)
代码页有很多,以下是常见的代码页。
代码页 Code Page |
说明 |
CP_ACP = 0 |
ANSI 编码代码页 (ANSI code page), ANSI 本地编码:中国大陆:936, 中国港台:950,美国:1252,…… |
CP_OEMCP = 1 |
OEM 代码页 (OEM code page), ASCII/DOS 本地编码:中国大陆:936, 中国港台:950,美国:437,…… |
CP_MACCP = 2 |
Macintosh 代码页 (MAC code page),早期的苹果代码页 |
CP_THREAD_ACP = 3 |
当前线程的 ANSI 代码页 (Current thread’s ANSI code page) |
CP_SYMBOL = 42 |
符号 (SYMBOL) |
437 |
ASCII (美国信息交换标准代码), DOS-USA,正宗的 ASCII 是美国的编码,不支持汉字或其他国家文字的! 两个 ASCII 表示一个汉字是 CP_ACP / CP_OEMCP 即 ANSI / ASCII 本地编码。 |
850 |
DOS 拉丁语 (DOS-LATIN1) |
936 |
GBK (国标扩展码/国标码), 中国大陆 (Chinese Main Land),新加坡 (Singapore) |
950 |
BIG5 (大五码), 中国台湾 (Chinese Taiwan), 中国香港 (Chinese Hongkong) |
932 |
Shift-JIS, 日语 (Japanese) |
949 |
韩国语 (Korean) |
874 |
泰国语 (Thai) |
1200 |
UTF-16 |
1201 |
UTF-16BE (UTF-16 Big Endian) |
1250 |
东欧 (Eastern Europe) |
1251 |
西里尔 Windows 系统 (Cyrillic Windows),俄语 Windows 系统 |
1252 |
西方语言-拉丁语1 (Western Latin 1),美国 Windows 用的是 1252,美国 DOS 用的是 437 (ASCII) |
1253 |
希腊语 (Greek) |
1254 |
土耳其语 (Turkish) |
1255 |
希伯来语 (Hebrew),以色列 |
1256 |
阿拉伯语 (Arabic) |
1257 |
波罗的海 (Baltic),立陶宛、拉脱维亚、爱沙尼亚等 |
1258 |
越南语 (Vietnamese) |
20866 |
西里尔/斯拉夫8位编码,Cyrillic KOI8-R,俄语、保加利亚语等 |
20936 |
简体中文 GB2312,早期汉字编码,现在多数情况都使用 936 代码页 |
54936 |
简体中文 GB18030,在 GBK 双字节编码的基础上,增加了 4 个字节的汉字编码,总共收录了 70,244 个汉字。 现在多数情况都使用 936 代码页,CP 54936 有很大的兼容性问题,要使用更多汉字编码的情况,一般都采用 UNICODE 的 CJK/CJKV 统一编码,收录了更多的汉字,而且提供了更好的兼容性 (全世界统一的编码)。 |
CP_UTF7 = 65000 |
UTF-7 |
CP_UTF8 = 65001 |
UTF-8 |
65005 |
UTF-32 |
65006 |
UTF-32BE (UTF-32 Big Endian) |
|