收藏 分享(赏)

常用编码详解.doc

上传人:dcjskn 文档编号:9221803 上传时间:2019-07-30 格式:DOC 页数:14 大小:54KB
下载 相关 举报
常用编码详解.doc_第1页
第1页 / 共14页
常用编码详解.doc_第2页
第2页 / 共14页
常用编码详解.doc_第3页
第3页 / 共14页
常用编码详解.doc_第4页
第4页 / 共14页
常用编码详解.doc_第5页
第5页 / 共14页
点击查看更多>>
资源描述

1、常用编码详解关键字:UCS,BMP,Unicode,GB2312,UTF-8,UTF7,编码摘要:本文在对各种资料整理后详细介绍各种常见编码的转换算法。一、通用字符集(UCS)ISO/IEC 10646-1 ISO-10646定义了一种多于 8比特字节的字符集,称作通用字符集(UCS),它包含了世界上大多数可书写的字符系统。已定义了两种多 8比特字节编码,对每一个字符采用四个 8比特字节编码的称为 UCS-4,对每一个字符采用两个 8比特字节编码的称为 UCS-2。它们仅能够对 UCS的前 64K字符进行编址,超出此范围的其它部分当前还没有分配编址。二、基本多语言面(BMP)ISO 10646

2、 定义了一个 31位的字符集。 然而,在这巨大的编码空间中,迄今为止只分配了前 65534个码位 (0x0000 到 0xFFFD)。 这个 UCS的 16位子集称为 “基本多语言面 ”(Basic Multilingual Plane, BMP)。 三、Unicode 编码历史上, 有两个独立的, 创立单一字符集的尝试。 一个是国际标准化组织(ISO)的 ISO 10646 项目; 另一个是由(一开始大多是美国的)多语言软件制造商组成的协会组织的 Unicode 项目。幸运的是, 1991年前后, 两个项目的参与者都认识到: 世界不需要两个不同的单一字符集。它们合并双方的工作成果,并为创立一

3、个单一编码表而协同工作。 两个项目仍都存在并独立地公布各自的标准, 但 Unicode 协会和 ISO/IEC JTC1/SC2 都同意保持 Unicode 和 ISO 10646 标准的码表兼容, 并紧密地共同调整任何未来的扩展。Unicode 标准额外定义了许多与字符有关的语义符号学, 一般而言是对于实现高质量的印刷出版系统的更好的参考。四、UTF-8 编码UCS-2和 UCS-4编码很难在许多当前的应用和协议中使用,这些应用和协议假定字符为一个 8或 7比特的字节。即使新的可以处理 16比特字符的系统,却不能处理 UCS-4数据。这种情况导致一种称为 UCS转换格式(UTF)的发展,它每

4、一种有不同的特征。 UTF-8(RFC 2279),使用了 8比特字节的所有位,保持全部 US-ASCII取值范围的性质:US-ASCII 字符用一个 8比特字节编码,采用通常的 US-ASCII值,因此,在此值下的任何一个 8比特位字节仅仅代表一个 US-ASCII字符,而不会为其他字符。它有如下的特性:1)UTF-8 向 UCS-4,UCS-2 两者中任一个进行相互转换比较容易。2)多 8比特字节序列的第一个 8比特字节指明了系列中 8比特字节的数目。3)8 比特字节值 FE和 FF永远不会出现。4)在 8比特字符流中字符边界从哪里开始较容易发现。UTF-8定义:在 UTF-8中,字符采用

5、 1到 6个 8比特字节的序列进行编码。仅仅一个 8比特字节的一个序列中,字节的高位为 0,其他的 7位用于字符值编码。n(n1)个 8比特字节的一个序列中,初始的 8比特字节中高 n位为 1,接着一位为 0,此字节余下的位包含被编码字符值的位。接着的所有 8比特字节的最高位为 1,接着下一位为 0,余下每个字节 6位包含被编码字符的位。下表总结了这些不同的 8比特字节类型格式。字母 x指出此位来自于进行编码的 UCS-4字符值。UCS-4范围(16 进制) UTF-8 系列(二进制)0000 00000000 007F 0xxxxxxx0000 00800000 07FF 110xxxxx

6、10xxxxxx0000 08000000 FFFF 1110xxxx 10xxxxxx 10xxxxxx0001 0000001F FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx0020 000003FF FFFF 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx0400 00007FFF FFFF 1111110x 10xxxxxx . 10xxxxxx从 UCS-4 到 UTF-8 编码规则如下:1)从字符值和上表第一列中决定需要的 8比特字节数目。着重指出的是上表中的行是相互排斥的,也就是说,对于一个给定的 UC

7、S-4字符,仅仅有一个有效的编码。2)按照上表中第二列每行那样准备 8比特字节的高位。3)将 UCS字符值的位,从低位起填充在标记为 x地方。从 UTF8序列中最后一个字节填起,然后剩下的字符值依次放到前一个字节中,如此重复,直到所有标记位 x的位都进行了填充。这里我们仅仅实现 Unicode到 UTF8的转换,Unicode 都是两个字节,定义为:typedef usigned short WCHAR/ 输出的 UTF8编码至多是 3个字节。int UnicodeToUTF8(WCHAR ucs2, unsigned char *buffer)memset(buffer, 0, 4);if

8、(0x0000 6) return 2;if (0x0800 6) buffer0 = 0xe0 | char(ucs2 12) return 3;return 0; 理论上,简单的通过用 2个 0值的 8比特字节来扩展每个 UCS-2字符,则从 UCS-2到 UTF-8编码的算法可以从上面得到。然而,从 D800到 DFFF间的 UCS-2值对(用 Unicode说法是代理对),实际上是通过 UTF-16来进行 UCS-4字符转换,因此需要特别对待:UTF-16转换必须未完成,先转换到于 UCS-4字符,然后按照上面过程进行转换。从 UTF-8到 UCS-4解码过程如下:1)初始化 UCS-

9、4字符 4个 8比特字节的所有位为 0。2)根据序列中 8比特字节数和上表中第二列(标记为 x位)来决定哪些位编码用于字符值。3)从编码序列分配位到 UCS-4字符。首先从序列最后一个 8比特字节的最低位开始,接着向左进行,直到所有标记为 x的位完成。如果 UTF-8序列长度不大于 3个 8比特字节,解码过程可以直接赋予 UCS-2。WCHAR UTF8ToUnicode(unsigned char *buffer)WCHAR temp = 0;if (buffer0 0) / if some bits in buffer, then output themindex = (bitBuffer

10、 = 6) nbits -= 6;index = (bitBuffer nbits) / output the high 6 bits*s+ = base64index;return (s - head);说明:对于合法的 Unicode字符数组,可以通过逐个输入数组中的字符,连续调用上面的函数,得到一个 UTF-7字节序列。需要说明的是:最后一个 Unicode字符应该是上面三个字节数组中某个字符的等值。下面,我们实现一个简单的说明函数,功能是:输入一个 UTF-7字节,可能得到并返回一个合法 Unicode字符;也可能不能得到,比如遇到+或者因为还没有完成一个字符的拼装,这时返回一个标志字

11、符 0xfeff,这个字符常用来标志 Unicode编码。注:函数影响了 state,nbits,bitBuffer 三个全局变量。在开始处理第一个字节时候,变量需要被初始化为:state = IN_ASCII;nbits = 0;bitBuffer = 0;#define RET0 0xfeffWCHAR UTF7ToUnicode(byte c)if(state = IN_ASCII) if (c = +) state = AFTER_PLUS;return RET0; else return (WCHAR)c;if (state = AFTER_PLUS) if (c = -) retu

12、rn (WCHAR)+; else state = IN_BASE64;nbits = 0;bitBuffer = 0; / it is not necessary/ dont return yet, continue to the IN_BASE64 mode/ state = Base64 if (byteTypec return (WCHAR)(bitBuffer nbits) return RET0;/ encount a byte which is not in base64 character set, switch out of base64 codingstate = IN_A

13、SCII;if (c != -) return (WCHAR)c;return RET0;说明:对于一个 UTF-7序列,可以通过连续输入字节并调用上面的函数,判断返回值,得到一个 Unicode字符数组。六、GB2312 编码中汉字的确定最早,表示汉字的区位码中,分为 94个区,每个区 94个汉字,1-15 区是西文字符,图形等,16-5 为一级汉字,56-87 为二级汉字,87 区以上为新字用。而我们在 Windows默认的编码,GB2312(1981 年国家颁布的信息交换用汉字编码字符集基本集)国标码,和区位码的换算为:国标码 = 区位码 + 2020H 而在汉字在计算机内表示的时候为保

14、证 ASCII码和汉字编码的不混淆,又做了一个换算:汉字机内码 = 国标码 + 8080H所以,真正的在 Windows上的 GB2312汉字编码是机内码,从上边的两个公式可以得到的就是:汉字机内码 = 区位码 + a0a0H一个汉字的编码最少要 a0a0H,因此我们在 CString中辨别汉字的时候可以认为:当一个字符的编码大于 a0的时候它应该是汉字的一个部分。但是也有特殊的情况的,不是每个汉字的两个字节编码都是大于 a0H的,例如镕的编码是 E946,后面的部分就不满足大于 a0H的条件。七、Windows 下多字节编码和 Unicode的转换Windows提供了 API函数,可以把 U

15、nicode字符数组转换为 GB2312字符串。其中,Unicode数组在传入时候最后一个为 0,也就是所谓的 null termidated字符串。在函数内部得到要返回字节串的大小,请求空间,进行真正的转换操作,指针在外部使用后释放,或者在类中加如其他的操作来处理,比如析构函数中释放。返回值为写到字节串里数目。int StringEncode:UnicodeToGB2312(char *dest, const WCHAR *src)char* buffer;int size = :WideCharToMultiByte(CP_ACP, 0, src, -1, NULL, 0, NULL, N

16、ULL); / null termidated wchars bufferbuffer = new charsize;int ret = :WideCharToMultiByte(CP_ACP, NULL, src, -1, buffer, size + 1, NULL, NULL);if (*dest != 0)delete *dest;*dest = buffer;return ret;注:其中见到有人在使用的时候,申请缓冲区空间时候是申请了(zise + 1)个来,最后一个字节写0,结束字符串。但是在我调试时候发现:系统给的 size已经包含了一个写入0的字节,而且最后得到的串中,0是已

17、经被系统 API写入了。(也许我的实验有错误,有待验证)。把 Unicode字符数组转换为 UTF-8和 UTF-7的方法类似,只要是WideCharToMultiByte函数的第一个表示代码页参数改为 CP_UTF7(65000)和CP_UTF8(65001)。同样道理,把多字节转换为 Unicode字符数组,也有相应的函数。和上面的函数类似,可以通过先提供一个空缓冲区而先得到需要的大小,然后开辟空间得到最后的字符数组。但是考虑到效率,可以适当牺牲一些空间,提供一个足够大的字符数组,数组大小在极端的情况下(全是 ASCII)是和字节数组大小一样的。int StringEncode:Gb231

18、2ToUnicode(WCHAR *dest, const char *src)int length = strlen(src); / null terminated bufferWCHAR *buffer = new WCHARlength + 1; / WCHAR means unsinged short, 2 bytes/ provide enough buffer size for Unicodesint ret = :MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, src, length, buffer, length);bufferret =

19、 0;if (*dest != 0)delete *dest;*dest = buffer;return ret;注:删除以前的缓冲区时候的操作,其实没有必要判断是不是为空,因为删除空指针是没有问题的,因为 delete内部提供了这样的机制。八、URL 解码用 IE发送 GET请求的时候,URL 是用 UTF-8编码的,当对截包数据分析时候就需要对数据解码,下面的函数是一个简单的实现:CString CTestUrlDlg:UrlToString(CString url)CString str = “;int n = url.GetLength();url.MakeLower();BYTE a

20、, b1, b2;for (int i=0; i= 0) elsed = 0;return d; static void UnicodeToGB2312(const WCHAR unicode, char* buffer)/ int size = :WideCharToMultiByte(CP_ACP, 0, unicode, -1, NULL, 0, NULL, NULL); int ret = :WideCharToMultiByte(CP_ACP, NULL, CString CTestUrlDlg:Uft8ToGB(CString url)CString str = “;char bu

21、ffer3;WCHAR unicode;unsigned char * p = (unsigned char *)(LPCTSTR)url;int n = url.GetLength();int t = 0;while (t n)unicode = UTF8ToUnicode(p, t);UnicodeToGB2312(unicode, buffer);buffer2 = 0;str += buffer;return str;示例: CString str = “/MFC%E8%8B%B1%E6%96%87%E6%89%8B%E5%86%8C.chm“;CString ret = UrlToString(str);ret = Uft8ToGB(ret); / MFC英文手册.chm九、总结常见算法还有 MIME等,由于篇幅限制,并且网上已经有很多帖子,在此不再赘述。对于本文,由于个人能力有限,难免有疏漏的地方,还望指教,共同进步。

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 企业管理 > 管理学资料

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报