[学习记号 - 其他] 针对 Silverlight 应用程序使用的 GB2312编码
来源:互联网 发布:python高级编程 pdf 编辑:程序博客网 时间:2024/06/05 16:36
1. 不支持流操作
2. 没有回退策略
3. 只实现了解码没有实现编码
4. 运行错误结果太多
5. 支持的字符数目过少
对于上面出现的众多问题,特发布了一个专门针对 Silverlight 应用程序使用的 GB2312Encoding,首先需要了解的知识:.NET Framework 中的字符编码,GB2312,EUC(Extended Unix Code),GB2312 是一种兼容 ASCII 编码的双字节字符编码,一个 Char 可以占用一个字节或两个字节,如果是占用两个字节,那么其第一个字节一定是 LEAD_BYTE,这样就可以区分一个 Char 是占用一个字节还是两个字节。在 GB2312 中,LEAD_BYTE 是 0x81~0xFE。
在实际中,Encoding 执行分为两种情况:
直接调用:即直接调用 Encoding 实体进行解码和编码操作,可以用如下的代码表示:
static string Decode(byte[] bytes) { Encoding encoding = Encoding.Default; return encoding.GetString(bytes); } static byte[] Encode(string str) { Encoding encoding = Encoding.Default; return encoding.GetBytes(str); }
在 Encoding 内部最终调用的过程是,先调用 GetCharCount 和 GetByteCount 方法得知解码和编码后的数组长度,然后再创建一个相应大小和类型的数组传递给 GetChars 和 GetBytes 方法,最后得到最终结果。这样,需要完成的重载是:
public override int GetCharCount(byte[] bytes, int index, int count) public override int GetChars(byte[] bytes, int byteIndex, int byteCount, char[] chars, int charIndex) public override int GetByteCount(char[] chars, int index, int count) public override int GetBytes(char[] chars, int charIndex, int charCount, byte[] bytes, int byteIndex)
间接调用:即通过 StreamReader 和 StreamWriter 间接调用 Encoding,以 StreamReader 读取 Stream 为例进行说明(StreamWriter 的过程类似):
1. 获取 encoding 的 Decoder
2. 创建一个长度最小为 bufferSize = 1024 bytes 的 byteBuffer
3. 获取到 _maxCharsPerBuffer = encoding.GetMaxCharCount(bufferSize)
4. 创建一个长度为 _maxCharsPerBuffer 的 charBuffer
5. 读取一个 byteBuffer 片段
6. 把 byteBuffer 传递给 decoder.GetChars,并获取片段的解码结果
7. 如果 stream 未读完,跳转到 5,否则进行下一步
8. 把获取到的解码片段组合成最终结果
以上结论可以在如下地方找到证据:
private void System.IO.StreamReader.Init(Stream, Encoding, bool, int); private int System.IO.StreamReader.ReadBuffer(char[], int, int, out bool); public override string System.IO.StreamReader.ReadToEnd();
从这个过程可以看出两个问题:
1. 对数据片段进行解码调用的是 decoder 而不是 encoding
2. 在进行片段进行解码的过程中,如果出现了片段的最后一个字节为 LEAD_BYTE 的情况,如何保存这一位数据到下一次调用时使用
第一个问题的出现是为了能够解决第二个问题,因为在构造 StreamReader 的时候会获取一个新的 Decoder 实例,这个新的实例很重要。在执行完第 6 步发现最后一位是 LEAD_BYTE,这时可以把 LEAD_BYTE 保存在 decoder 中,因为 .net 中多个实例可以共用同一个 Encoding,所以在 Encoding 实例中不能够存储任何与编码解码有关的状态信息,同时每个 StreamReader 实例对应一个唯一的 Decoder 实例,所以 LEAD_BYTE 的状态是可以保证的。这样,需要完成的重载是:
public override int GetMaxByteCount(int charCount) public override int GetMaxCharCount(int byteCount) public override Decoder GetDecoder()
回退策略
因为在编码和解码过程中并不是所有的字符在两个字符集中都是一一对应的,很可出现某个字符存在于这个字符集但不存在另外一个字符集的情况,所以必须有正确的回退机制处理此类问题。在 Fx 4.0 中支持“最佳回退”“替换回退”“异常回退”三种策略,但由于本文的目的是解决 Silverlight 中的 GB2312 支持问题,同时在 Silverlight 中并没有公开的回退策略,所以本文只选用了简化的“替换回退”策略:遇到不可处理的数据,一律替换成“?”(0x3F)。
结束语:
- 从零开始的做一个 Encoding 是非常复杂的,本文不可能面面俱到,还请谅解
- 此项目在发布前做了非常大量的测试,所用的测试样例覆盖了目前所能想到的方方面面,并且与 Fx 4.0 的 gb2312 encoding 进行了对比,所以大家可以放心的使用此项目
- 虽然说这是 GB2312 的 Encoding,但其中的实现方法是按照双字节字符集 (DBCS) 的编码方法实现的,所以,只需要替换掉相应的数据文件,就可以支持其他的 DBCS 编码
- 没有提到如何生成数据文件
- 此项目已经发布到 Codeplex:http://gb2312.codeplex.com/
- 最新源码下载地址: http://gb2312.codeplex.com/releases/view/75550#DownloadId=295597(2011/10/22)
- 此项目使用 Microsoft Reciprocal License (Ms-RL) 授权协议
- 本文来自Aimeast的博客,原文地址:http://www.cnblogs.com/Aimeast/archive/2011/10/23/2221542.html
- [学习记号 - 其他] 针对 Silverlight 应用程序使用的 GB2312编码
- [学习记号 - SL其他] Silverlight资源引用路径总结
- 使用记号的cvCopy
- 记号(notation)的学习
- [学习记号 - SL代码] Silverlight可拖放工具类
- GB2312的编码规则
- GB2312的编码规则
- GB2312的编码规则
- Silverlight GB2312
- iOS下如何将UTF8字符串转换为GB2312字符串(或者其他编码的字符串)
- 使用tidy_win32.zip转换GB2312编码的HTML页面
- 使用tidy_win32.zip转换GB2312编码的HTML页面
- qt4.3.3在VC6中使用gb2312编码的bug
- Windows Phone 8.1 无法使用GB2312编码的解决方案
- SilverLight商业应用程序开发---学习笔记(7) DataGrid控件的使用
- Silverlight 教程 做个记号
- 常用汉字的GB2312 编码
- 记号 Android操作系统上的应用程序远程调试
- Some RAC Concepts
- 一串事物中每个事物的前后位置与顺序编号的转换问题
- mysql 添加列,修改列,删除列。
- Android 网络时间更新-科卓培训android系列
- openwrt目录结构
- [学习记号 - 其他] 针对 Silverlight 应用程序使用的 GB2312编码
- WCF Note5(Binding)
- UITableView实现下拉刷新添加数据功能
- 嵌入式系统Boot Loader技术内幕
- Spring 2.5.1 MVC + Tiles 2.0.5 基本配置
- 单例模式浅理解
- S3C2440 SDRAM内存驱动
- UVa Problem 10177 (2/3/4)-D Sqr/Rects/Cubes/Boxes? (2/3/4-维立方体?)
- openwrt配置文件解读