【初尝博客】Unity Web Player不支持GB2312的解决办法

来源:互联网 发布:宝葫芦软件 编辑:程序博客网 时间:2024/06/05 08:57

  开始正题之前请允许我先碎碎念一下:其实这是本人第一次写博客,之前也经常看一下大牛的博客,心里都是满满的羡慕,不是被他们的文采所吸引,就是被他们极具深度的技术分析所折服。心里总想如果我能写出这样的博文该多好,但是总是停留在“想”的层面上,从来没有付诸实践,因为知道即使你懂了某个知识点,一项技术,解决了一个问题,但是距离表达出来,并让人所理解之间还存在一条鸿沟,所以迟迟不敢尝试,这次也是鼓足了勇气。因个人水平有限,可能写的不好,或者写的不全,甚至也有可能写错的地方,毕竟第一次写,也不知道怎么写才能把自己想表达的表达清楚,希望各位多多包涵,如有发现错误,还希望能够指出,大家一起学习,一起进步。
如有可借鉴之处,转载时请注明出处: http://blog.csdn.net/yiyikela/article/details/45335847

谁偷了我的数据

  这还得从某次做项目说起。当时项目要求,必须用unity获取某服务器上的数据,通过客户端发送不同的请求,得到服务器回发的数据(GB2312编码的数据),而且项目最终是要发布成web版的。接下来我便在unity中进行测试,在Unity的Game视窗中成功打印出了接收到的数据,然后发布到PC平台,所有的动作一气呵成。运行exe程序。。。。。咦?怎么回事?只见程序运行界面一片蓝,空荡荡的,什么都没有。服务器发过来的数据呢?一般情况下,发布成PC端的结果和unity编辑下的结果是一致的,问题出在了哪里呢?关键是什么错误信息都没有,紧接着,又是一番测试,最终将问题锁定在”Encoding.GetEncoding(“GB2312”).GetString()“这句代码上,将代码扔进try{}catch{}块中,打印出了异常信息:
        'GB2312'  not supported
                      异常信息:不支持GB2312编码
知道问题出在哪里就有办法解决了,问了一下度娘,发现问这个问题的人真的是少之又少,好在终于在unity连接mysql数据库(测试通过)里找到了关于此问题的解决方案。根据博客中所说,我测试了一下,其实只需将I18N.CJK.dll动态链接库导入项目中的assets文件夹下,发布成exe文件,即可成功打印出GB2312编码的数据。接下来,把项目发布成web版,发布直接报错,无法发布,我只好尝试着将上述博客中提到的I18N.dll以及I18N.West.dll扔到assets下,庆幸的是可以正常发布了,但是,打开后,又是另外一串异常信息:
        调用目标异常
                      web版异常信息:目标调用异常
调用目标异常,未找到调用的方法。谷歌、百度找个遍,未果。。。(如有大神有此问题的解决方案,或者是思路,还请不吝赐教,多谢!)

编写自己的转码程序

  显然事情的发展不应该这样的,虽然没有找到这个错误的解决办法,但是项目依然要继续啊,既然unity没有提供便捷的支持GB2312的方法,那就自己写一个转码程序吧。解决思路:unity对unicode编码提供良好的支持,所以可以将GB2312字节流中的字节码转化成相对应unicode的字节码,然后再用自带的unicode解析出来。

计算机字符编码

  关于计算机字符编码的知识,此处不作赘述,网上的资料非常多。可参考:字符编码或者ASCII 、GB2312、GBK、GB18030、unicode、UTF-8字符集编码详解GB2312、 utf-8编码原理以及其他相关资料。本文仅阐述有关GB2312和Unicode的几个重点知识。首先,我们先来看一个例子:

byte[] bufGB2312 = Encoding.GetEncoding("GB2312").GetBytes("GB2312测试");byte[] bufUnicode = Encoding.Unicode.GetBytes("GB2312测试");

相同的字符串,采用不同的编码,它们的字节码又是什么呢?
             这里写图片描述
                      GB2312字节码(左) Unicode字节码(右)
  从图中,我们大致可以看出以下几点:
 ● GB2312采用一个字节表示原有的ASCII码,应该可以说是向下兼容ASCII码;而Unicode在原有ASCII码的基础上,高字节上还补了0,用两个字节来表示原有的ASCII码;
 ● 在表示汉字方面,GB2312与Unicode均采用了两个字节来表示,且字节码完全不同。
  而这正我们要谈的重点,也就是GB2312与Unicode的编码规则,因为只有掌握了编码规则,了解了两者的区别与联系,才能对它们进行转换。正如我们所看的那样,GB2312采用一个字节表示ASCII码,用两个字节表示汉字,ASCII码的范围是:0x00-0x7F,汉字的编码范围是:0xA1A1-0xF7FE。既然是一个字节和两个字节混合使用,那怎么知道什么时候使用一个字节来解析,什么时候该使用两个字节来解析呢?细心的网友可能会发现,GB2312的汉字编码的范围,无论是高字节,还是低字节,都大于ASCII的最大表示值0x7F,所以我们就可以判断,只要一个字节小于A1,那么这个字节一定是表示ASCII值,反之,则与后一个字节一起表示一个汉字。而Unicode编码采用的双字节编码,即使针对原ASCII码也从单字节扩展成了双字节。(关于Unicode的具体资料可查看:Unicode字符编码规范)那么GB2312与Unicode又有什么联系呢?很遗憾,事实上它们之间并没有什么联系,除了在ASCII码的编码上有些关联。那我们应该如何实现它们之间的转换呢?如果我们能找到一张表,表中有GB2312和Unicode对于相同字符的一一映射关系,那么我们的问题也就迎刃而解了。庆幸的是,我在网上找到了这张它们映射关系的表,现在可以开始着手编写程序了。 

My Decoder

  关于此编码转化程序,我在网上找到了C版本的,附上下载地址:C语言版的GB2312-Unicode转化程序。参考了C语言版本的转化程序,便开始写自己C#版的转化程序。
  1、定义一个只读数组,用于存储映射表中所有字符编码(截取部分表内容):

        private static readonly int[] GB2312ToUnicode ={                0xA1A1,0x3000,/* ' ' -> 12288 */                0xA1A2,0x3001,/* '、' -> 12289 */                0xA1A3,0x3002,/* '。' -> 12290 */                0xA1A4,0x30FB,/* '·' -> 12539 */                0xA1A5,0x02C9,/* 'ˉ' ->   713 */                0xA1A6,0x02C7,/* 'ˇ' ->   711 */                0xA1A7,0x00A8,/* '¨' ->   168 */                0xA1A8,0x3003,/* '〃' -> 12291 */                0xA1A9,0x3005,/* '々' -> 12293 */                0xA1AA,0x2015,/* '—' ->  8213 */                0xA1AB,0xFF5E,/* '~' -> 65374 */                0xA1AC,0x2016,/* '‖' ->  8214 */                0xA1AD,0x2026,/* '…' ->  8230 */                0xA1AE,0x2018,/* '‘' ->  8216 */                0xA1AF,0x2019,/* '’' ->  8217 */                0xA1B0,0x201C,/* '“' ->  8220 */                ……                0xD6DD,0x5DDE,/* '州' -> 24030 */                0xD6DE,0x6D32,/* '洲' -> 27954 */                0xD6DF,0x8BCC,/* '诌' -> 35788 */                0xD6E0,0x7CA5,/* '粥' -> 31909 */                0xD6E1,0x8F74,/* '轴' -> 36724 */                0xD6E2,0x8098,/* '肘' -> 32920 */                0xD6E3,0x5E1A,/* '帚' -> 24090 */                0xD6E4,0x5492,/* '咒' -> 21650 */                0xD6E5,0x76B1,/* '皱' -> 30385 */                0xD6E6,0x5B99,/* '宙' -> 23449 */                0xD6E7,0x663C,/* '昼' -> 26172 */                0xD6E8,0x9AA4,/* '骤' -> 39588 */                0xD6E9,0x73E0,/* '珠' -> 29664 */                0xD6EA,0x682A,/* '株' -> 26666 */                0xD6EB,0x86DB,/* '蛛' -> 34523 */                0xD6EC,0x6731,/* '朱' -> 26417 */                0xD6ED,0x732A,/* '猪' -> 29482 */                0xD6EE,0x8BF8,/* '诸' -> 35832 */                0xD6EF,0x8BDB,/* '诛' -> 35803 */                0xD6F0,0x9010,/* '逐' -> 36880 */                0xD6F1,0x7AF9,/* '竹' -> 31481 */                0xD6F2,0x70DB,/* '烛' -> 28891 */                0xD6F3,0x716E,/* '煮' -> 29038 */                0xD6F4,0x62C4,/* '拄' -> 25284 */                0xD6F5,0x77A9,/* '瞩' -> 30633 */                0xD6F6,0x5631,/* '嘱' -> 22065 */                0xD6F7,0x4E3B,/* '主' -> 20027 */                0xD6F8,0x8457,/* '著' -> 33879 */                0xD6F9,0x67F1,/* '柱' -> 26609 */                0xD6FA,0x52A9,/* '助' -> 21161 */                0xD6FB,0x86C0,/* '蛀' -> 34496 */                0xD6FC,0x8D2E,/* '贮' -> 36142 */                0xD6FD,0x94F8,/* '铸' -> 38136 */                0xD6FE,0x7B51,/* '筑' -> 31569 */                0xD7A1,0x4F4F,/* '住' -> 20303 */                0xD7A2,0x6CE8,/* '注' -> 27880 */                0xD7A3,0x795D,/* '祝' -> 31069 */                0xD7A4,0x9A7B,/* '驻' -> 39547 */                0xD7A5,0x6293,/* '抓' -> 25235 */                0xD7A6,0x722A,/* '爪' -> 29226 */                0xD7A7,0x62FD,/* '拽' -> 25341 */                0xD7A8,0x4E13,/* '专' -> 19987 */                0xD7A9,0x7816,/* '砖' -> 30742 */                0xD7AA,0x8F6C,/* '转' -> 36716 */                0xD7AB,0x64B0,/* '撰' -> 25776 */                0xD7AC,0x8D5A,/* '赚' -> 36186 */                0xD7AD,0x7BC6,/* '篆' -> 31686 */                0xD7AE,0x6869,/* '桩' -> 26729 */                0xD7AF,0x5E84,/* '庄' -> 24196 */                0xD7B0,0x88C5,/* '装' -> 35013 */                0xD7B1,0x5986,/* '妆' -> 22918 */                0xD7B2,0x649E,/* '撞' -> 25758 */                0xD7B3,0x58EE,/* '壮' -> 22766 */                0xD7B4,0x72B6,/* '状' -> 29366 */                0xD7B5,0x690E,/* '椎' -> 26894 */                0xD7B6,0x9525,/* '锥' -> 38181 */                0xD7B7,0x8FFD,/* '追' -> 36861 */                0xD7B8,0x8D58,/* '赘' -> 36184 */                0xD7B9,0x5760,/* '坠' -> 22368 */                0xD7BA,0x7F00,/* '缀' -> 32512 */                0xD7BB,0x8C06,/* '谆' -> 35846 */                0xD7BC,0x51C6,/* '准' -> 20934 */                0xD7BD,0x6349,/* '捉' -> 25417 */                0xD7BE,0x62D9,/* '拙' -> 25305 */                0xD7BF,0x5353,/* '卓' -> 21331 */                0xD7C0,0x684C,/* '桌' -> 26700 */                0xD7C1,0x7422,/* '琢' -> 29730 */                0xD7C2,0x8301,/* '茁' -> 33537 */                0xD7C3,0x914C,/* '酌' -> 37196 */                0xD7C4,0x5544,/* '啄' -> 21828 */                0xD7C5,0x7740,/* '着' -> 30528 */                0xD7C6,0x707C,/* '灼' -> 28796 */                0xD7C7,0x6D4A,/* '浊' -> 27978 */                0xD7C8,0x5179,/* '兹' -> 20857 */                0xD7C9,0x54A8,/* '咨' -> 21672 */                0xD7CA,0x8D44,/* '资' -> 36164 */                0xD7CB,0x59FF,/* '姿' -> 23039 */                0xD7CC,0x6ECB,/* '滋' -> 28363 */                0xD7CD,0x6DC4,/* '淄' -> 28100 */                0xD7CE,0x5B5C,/* '孜' -> 23388 */                0xD7CF,0x7D2B,/* '紫' -> 32043 */                0xD7D0,0x4ED4,/* '仔' -> 20180 */                0xD7D1,0x7C7D,/* '籽' -> 31869 */                0xD7D2,0x6ED3,/* '滓' -> 28371 */                0xD7D3,0x5B50,/* '子' -> 23376 */                0xD7D4,0x81EA,/* '自' -> 33258 */                0xD7D5,0x6E0D,/* '渍' -> 28173 */                0xD7D6,0x5B57,/* '字' -> 23383 */                0xD7D7,0x9B03,/* '鬃' -> 39683 */                0xD7D8,0x68D5,/* '棕' -> 26837 */                0xD7D9,0x8E2A,/* '踪' -> 36394 */                0xD7DA,0x5B97,/* '宗' -> 23447 */                0xD7DB,0x7EFC,/* '综' -> 32508 */                ……                };

  2、二分查找法:

        //采用二分查找法,查找与GB2312对应的Unicode码        private static int DichotomySearch(int[] array, int value, int high, int low)        {            int middle = 0;            if (high < low)            {                return -1;            }            middle = (low + high) / 2;            if (middle % 2 == 1)            {                middle++;            }            int i = array[middle];            if (array[middle] == value)            {                return middle;            }            else if (array[middle] > value)            {                return DichotomySearch(array, value, middle - 2, low);            }            else            {                return DichotomySearch(array, value, high, middle + 2);            }        }

  3、将GB2312字节码转成Unicode字节码:
  此处需注意一个细节,如“测”字的GB2312码为:0xB2E2,在内存中的存储方式是B2存储在低地址E2存储在高地址;而它的Unicode码为:0x6D4B,在内存中的存储方式是6D存储在高地址4B存储在低地址。所以在转换时应特别注意(可以参考上文不同编码的字节存储图)。

        public static string GBToUnicode(byte[] buffer,int length)        {            //使用list存储从GB2312转成Unicode的字节码            List<byte> data = new List<byte>();            int i = 0;            while (i < length)            {                //若字节码小于0xa1,说明表示ascii码,直接在高位补上0x00,即可转换成Unicode码                if (buffer[i] < 0xa1)                {                    data.Add(buffer[i]);                    data.Add(0x00);                    i++;                }                else                {                    int value = buffer[i];                    //GB2312将前一个字节与后一个字节组成一个汉字编码                    value = ((value << 8) & 0xff00) | (buffer[i + 1] & 0xff);                    //查找对应的Unicode编码                    int index = DichotomySearch(GB2312ToUnicode, value, GB2312ToUnicode.Length, 0);                    if (index == -1)                        return "";                    value = GB2312ToUnicode[index + 1];                    //将找到Unicode编码分成两个字节,分别存储在byte集合中                    int temp = (value >> 8) & 0xff;                    value = value & 0x00ff;                    data.Add((byte)value);                    data.Add((byte)temp);                    i += 2;                }            }            byte[] dataBuffer = new byte[data.Count];            //将Byte集合中的字节码存进byte[].            for (int j = 0; j < data.Count; j++)            {                dataBuffer[j] = data[j];            }            //输出字符编码所对应的字符串            return Encoding.Unicode.GetString(dataBuffer, 0, dataBuffer.Length);        }

  至此,编码转换程序也就完成了,当然,因为只是针对GB2312的转换,局限性比较强,但是如果有其他编码,原理也是一样的,只需要找到互转的编码表,即可实现转换。希望此博文可以帮助到大家。
  下载地址:C# GB2312转换程序

0 0