常用编码详解.doc_第1页
常用编码详解.doc_第2页
常用编码详解.doc_第3页
常用编码详解.doc_第4页
常用编码详解.doc_第5页
已阅读5页,还剩9页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

常用编码详解关键字: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 定义了一个31位的字符集。 然而,在这巨大的编码空间中,迄今为止只分配了前65534个码位 (0x0000 到 0xFFFD)。 这个UCS的16位子集称为 “基本多语言面 ”(Basic Multilingual Plane, BMP)。 三、Unicode编码历史上, 有两个独立的, 创立单一字符集的尝试。 一个是国际标准化组织(ISO)的 ISO 10646 项目; 另一个是由(一开始大多是美国的)多语言软件制造商组成的协会组织的 Unicode 项目。幸运的是, 1991年前后, 两个项目的参与者都认识到: 世界不需要两个不同的单一字符集。它们合并双方的工作成果,并为创立一个单一编码表而协同工作。 两个项目仍都存在并独立地公布各自的标准, 但 Unicode 协会和 ISO/IEC JTC1/SC2 都同意保持 Unicode 和 ISO 10646 标准的码表兼容, 并紧密地共同调整任何未来的扩展。Unicode 标准额外定义了许多与字符有关的语义符号学, 一般而言是对于实现高质量的印刷出版系统的更好的参考。四、UTF-8编码UCS-2和UCS-4编码很难在许多当前的应用和协议中使用,这些应用和协议假定字符为一个8或7比特的字节。即使新的可以处理16比特字符的系统,却不能处理UCS-4数据。这种情况导致一种称为UCS转换格式(UTF)的发展,它每一种有不同的特征。 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中,字符采用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 0xxxxxxx 0000 00800000 07FF 110xxxxx 10xxxxxx 0000 08000000 FFFF 1110xxxx 10xxxxxx 10xxxxxx 0001 0000001F FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 0020 000003FF FFFF 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 0400 00007FFF FFFF 1111110x 10xxxxxx . 10xxxxxx从UCS-4 到 UTF-8编码规则如下:1)从字符值和上表第一列中决定需要的8比特字节数目。着重指出的是上表中的行是相互排斥的,也就是说,对于一个给定的UCS-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 (0x0000 = ucs2) & (ucs2 = 0x007f)/ one char of UTF8 buffer0 = (char)ucs2; return 1; if (0x0080 = ucs2) & (ucs2 6) & 0x001f); return 2; if (0x0800 = ucs2) & (ucs2 6) & 0x003f); buffer0 = 0xe0 | char(ucs2 12) & 0x001f); 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-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 0x80) / one char of UTF8 temp = buffer0; if (0xc0 = buffer0) & (buffer0 0xe0) / two char of UTF8 temp = buffer0 & 0x1f; temp = temp 6; temp = temp | (buffer1 & 0x3f); if (0xe0 = buffer0) & (buffer0 0xf0) / three char of UTF8 temp = buffer0 & 0x0f; temp = temp 6; temp = temp | (buffer1 & 0x3f); temp = temp 6; temp = temp | (buffer2 & 0x3f); if (0x80 = buffer0) & (buffer0 0) / if some bits in buffer, then output them index = (bitBuffer (6 - nbits) & 0x3f; *s+ = base64index; if (byteTypetemp & BASE64) | (temp = -) *s+ = -; state = IN_ASCII; *s+ = temp; if (temp = +) *s+ = -; else if (state = IN_ASCII) *s+ = +; state = IN_BASE64; / begins base64 coding here nbits = 0; bitBuffer = 0; bitBuffer = 6) nbits -= 6; index = (bitBuffer nbits) & 0x3f; / output the high 6 bits *s+ = base64index; return (s - head);说明:对于合法的Unicode字符数组,可以通过逐个输入数组中的字符,连续调用上面的函数,得到一个UTF-7字节序列。需要说明的是:最后一个Unicode字符应该是上面三个字节数组中某个字符的等值。下面,我们实现一个简单的说明函数,功能是:输入一个UTF-7字节,可能得到并返回一个合法Unicode字符;也可能不能得到,比如遇到+或者因为还没有完成一个字符的拼装,这时返回一个标志字符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 = -) return (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 & BASE64) bitBuffer = 16) nbits -= 16; return (WCHAR)(bitBuffer nbits) & 0x0000ffff); return RET0; / encount a byte which is not in base64 character set, switch out of base64 coding state = IN_ASCII; if (c != -) return (WCHAR)c; return RET0;说明:对于一个UTF-7序列,可以通过连续输入字节并调用上面的函数,判断返回值,得到一个Unicode字符数组。六、GB2312编码中汉字的确定最早,表示汉字的区位码中,分为94个区,每个区94个汉字,1-15区是西文字符,图形等,16-5为一级汉字,56-87为二级汉字,87区以上为新字用。而我们在Windows默认的编码,GB2312(1981年国家颁布的信息交换用汉字编码字符集基本集)国标码,和区位码的换算为:国标码 = 区位码 + 2020H 而在汉字在计算机内表示的时候为保证ASCII码和汉字编码的不混淆,又做了一个换算:汉字机内码 = 国标码 + 8080H所以,真正的在Windows上的GB2312汉字编码是机内码,从上边的两个公式可以得到的就是:汉字机内码 = 区位码 + a0a0H一个汉字的编码最少要a0a0H,因此我们在CString中辨别汉字的时候可以认为:当一个字符的编码大于a0的时候它应该是汉字的一个部分。但是也有特殊的情况的,不是每个汉字的两个字节编码都是大于a0H的,例如镕的编码是 E946,后面的部分就不满足大于a0H的条件。七、Windows下多字节编码和Unicode的转换Windows提供了API函数,可以把Unicode字符数组转换为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, NULL); / null termidated wchars buffer buffer = 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是已经被系统API写入了。(也许我的实验有错误,有待验证)。把Unicode字符数组转换为UTF-8和UTF-7的方法类似,只要是WideCharToMultiByte函数的第一个表示代码页参数改为CP_UTF7(65000)和CP_UTF8(65001)。同样道理,把多字节转换为Unicode字符数组,也有相应的函数。和上面的函数类似,可以通过先提供一个空缓冲区而先得到需要的大小,然后开辟空间得到最后的字符数组。但是考虑到效率,可以适当牺牲一些空间,提供一个足够大的字符数组,数组大小在极端的情况下(全是ASCII)是和字节数组大小一样的。int StringEncode:Gb2312ToUnicode(WCHAR *dest, const char *src) int length = strlen(src); / null terminated buffer WCHAR *buffer = new WCHARlength + 1; / WCHAR means unsinged short, 2 bytes / provide enough buffer size for Unicodes int ret = :MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, src, length, buffer, length); bufferret = 0; if (*dest != 0) delete *dest; *dest = buffer; return ret;注:删除以前的缓冲区时候的操作,其实没有必要判断是不是为空,因为删除空指针是没有问题的,因为delete内部提供了这样的机制。八、URL 解码用IE发送GET请求的时候,URL是用UTF-8编码的,当对截包数据分析时候就需要对数据解码,下面的函数是一个简单的实现:CString CTestUrlDlg:UrlToString(CString url) CStringstr = ; int n = url.GetLength(); url.MakeLower(); BYTE a, b1, b2; for (int i=0; i= 0) & (c = a) & (c = A) & (c = F) d = c - A + 10; else d = 0; r

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论