确定性与字符集乱码

#确定性与字符集乱码
 计算机,其实是一个充满确定性的环境,所有的事情都按照预先设定的步骤有条不紊地执行!没有一点,计算机可以发挥自己的主动能动性,可能会做出有一点独立思想的随机选择!所以,在计算机世界里面我们看到的是没有灵异事件,优良的程序员绝对是一个唯物的无神论者。如果程序犯了错误,最终只要你找到原因,那么只有是苦命的程序员自己所犯的低级错误!
  
  在定位很多故障和问题的时候,我们经常有这样一种感性认识,在没有找到最后的解释前,往往到处都可能是暗流涌动,到处可能是蚁穴的沼泽地。但是,在你找到最后的答案,你发现一切都那么简单、自然、和谐!那是因为确定性对那里确定了法则,一切都按原则办事了。

 不幸的是,我们现在很多刚入道的程序员都以“程序能用就可以”的实用态度,来对待编程!从来没有一种积极主动的态度,也没有使积极主动成为一种良好的习惯!在虽然解决了问题,但是还是存在疑惑的时候,从来不从更为稳固的现象背后的内部机理上进行挖掘,从而取得对确定性的深刻把握!往往我看到的是,靠巧合、随机进行工作,只要表现没有错即可!My God,只有天知道,在这些陷阱遍布的软件系统丛林里,它在什么时候会遇到自己的撒旦,而有时谁会成为第一个倒霉蛋,来承担前辈所犯的错误!


 具有讽刺意义,持这样一种遇事深究态度的人并不多,而持有这些态度的人往往是另类!他们会面对一些人的诘难:只要会用就可以了,世间这么多东西,计算机发展这么快,一个人的力量能学的过来,能弄得清楚么?对此,失与巧言利色的我,只有哑笑和摇头。我经常所秉承的原则是,在不能影响它人的时间,只要能够要求得住自己就可以了。但是,曾经花费很大力气经历过的苦难,对于年长的人,总有一种说给同行人的欲望,总有一种不吐不快、鱼刺卡喉之感,希望写出来,对听弦之人能有所警示!个人认为,事情需要懂得更多一点,或更准确地说,懂得更深入一点,不光是为了对于确定性的更深入层次的把握,另外,它也可以成为一种思维能力的锻炼。所有的道理和理论到最后,在路的尽头都是大道同途!完整、深刻地理解了一个领域的知识,当你遇到另外一个陌生的领域,即使你可以不知道它是怎么实现的,只要你知道它的输入、输出映射关系,通俗点可以说是功能需求。凭照你的深厚积淀,你也可以对其内部的可能的行为描绘出八八九九。我们同时也可以看到,在一些成名高手的个人经验讲述中,往往将对一门语言的深刻把握,列到比较高要求位置。下面回到正题,呵呵,说了很多的题外牢骚话 :)


#字符集与数据解释
    当你面对内存区域或一段码流的时候,它的意义,确实犹如在我的前面一篇文章《指针漫谈》中所谈的,完全依赖于它的解释。而这个解释的依据,在确定性的影响下,可能会来自约定,可能会来自指示Flag,最末一种可能就是一种依据当地环境的默认选择了。字符集简单的来说,字符集就是规定了对于内存区域字符性质的数据,是解释的一个框架!注意,字符集也只是一种解释而已,还可能有很多解释呢!偶班门弄斧地学一下欧几里得前辈的形式化公理系统,首先定义一下问题的形式化描述:
---------------------------
|   Name |    (字符的内值) |       -> characterset -> 确定出每个内存区域的意义
---------------------------


#字符乱码的由来
  字符显示出现乱码,其实分了好几个阶段,特别在C/S、B/S架构下的应用程序,因为数据的生命周期跨越了多个阶段,每个阶段的一点差错都可以导致后面的谬以千里!我们可以根据字符数据生命周期流程的每一个阶段进行分析,乱码的可能。切不可简单地认为,只要一个地方控制住了,就可以解决整个过程的问题。太简单了,So Childish!如果字符集乱码问题如此的简单的话,网上也就没有很多共同的文章来讨论字符集了。乱码问题,我想根本上来说是一个数据解释的问题,这有点哲学层面的讨论了,呵呵!从再高一点的理解层次来说,我认为可以分为大致两类,按照粗浅的编程经历来说,首先是有数据处理的问题,再次也有客户端环境本身不支持所要求字符集显示的问题。其中,对字符码流进行“数据处理”出问题最多,特别表现在两点:第一,在不同的字符集范围内转来转去的时候;第二,出现对同一段码流的字符解释框架不一样上。


#一种常见的字符集乱码
  一些Web应用程序,常由于经典Http协议模型被动特征的限制,使得需要引入控件成为必要。只有通过这样的通信链路,才能把服务器端需要主动通知客户端的消息给传递下去。如果客户端和服务器端传递数据,只是数值信息的话,一般不需要考虑什么字符集问题,因为其不牵扯字符意义概念。但是,如果你的数据中传递有字符一级信息的时候,你经常需要作的事是常常一定要敲响自己警钟,你是在什么字符集框架内对其进行编码以及对方按照什么样的字符框架进行解码的。


  对于前面发的牢骚,我举出一种依靠一种幸运和巧合在工作应用场景吧!例如,Web页面依靠控件报的事件进行显示某些字符信息。我们知道微软的控件技术是支持国际化的。虽然,Build控件的时间有四种选择,但是我们可以依靠一种非国际化版本的做法,使得控件可以支持中文的传递,而实际上这种控件实现是依靠巧合取得成功。具体这个例子是这样作的,服务器端按照GBK将要显示字符传递给客户端控件,而控件实现的时间没有编译成为国际化版本,控件将得到的字符串利用memcpy“透传”性质地以“非Wide字符指针”传给脚本。这个过程在表面上没有明显的错误,也能够正常显示。但是,确实在依靠巧合编程。


    我猜想,巧合在于,当我们的脚本引擎接受到控件传递过来的内存拷贝后,它不知道投送过来的字符内存拷贝到底以何种字符集进行编码(??)。字符数据传递的流程走到这里,在信息意义上,已经丢失了很多服务器端的信息了,服务器端的伟大的辐射力在传递十万八千里后,在这里已淡如白水。但是,脚本引擎,必须以及一定要给它接受的字符信息以意义,才能完成,以一定的字符集解释投向JavaScript脚本内建以Unicode字符集上。请注意,JavaScript脚本有个很重要的特征,即以Unicode字符集对待自己的字符串操作。这时,脚本引擎这个时候别无它法,脚本引擎所能依据的,只有控件传过来的信息的字符串指针类型是非Wide字符,是非unicode字符,于是脚本引擎选择了可能最合乎情理的猜测,根据当前操作系统环境的语言设置,进行解析收到的码流,并转换到脚本内建的unicode字符集上。这时,你会发现这正好巧合上了,客户端起点按照GBK来对待接受到的字符信息,然后向Unicode转化的时间,而且脚本引擎选择的是向GBK自己的超集Unicode转换。我们利用非Wide宽字符实现了传递非USCII字符集的信息。确实,在中国的环境下,这种情况并不会出现问题!但是,你的字符码流解释,是于客户端的机器环境设置严格绑定的。当我们扩展这样的应用成为国家化的软件系统的时间,将遇到很令人头疼的问题--字符集乱码。


    扩展应用成为国际化版本,我们服务器,将最省事的做法是,统一地按照utf-8进行传递自己的信息,而不是依靠客户端机器设置分别进行不同的编码!同时,侦测客户端设置本来就是一个不容易的事情,特别是在Http架构下。我们传递到客户端的码流将是utf-8格式的,但是,如果控件向Web页面报事件的时间,解释我们的服务器端传送到客户端的码流将不是按照utf-8格式1、2、2不等字节地去解释信息,而会按照客户端机器环境,例如GBK,以一、两个字节的界长来解释字符码流!你很容易想象这时怪物出现了,脚本引擎对字符码流的解释是驴头不对马嘴的,但是,脚本引擎和控件都是被强迫当了歪嘴和尚并且念了歪经,它们只不过很无辜地、忠实地按照我们聪明程序员的设定进行工作的:)。
    再次,点明字符集乱码一般,一种会出现在字符集互转上,另外一种则出现对同一段码流的字符解释框架不一样上。
    #如何解决问题依赖确定性
         我们发现,如果想扩展这样的应用程序成为国际化版本,不修改控件的方式,就是服务器端能够按照不同的客户端环境进行不同的内容编码返还,脚本引擎将根据控件报事件的非w字符串指针的类型,按照客户端环境的语言设置进行解释。在整个服务器端和客户端的字符交换流程中维持其按照确定性去行走,不能让解释随意梦游。另外,一种最简单的实现是,服务器端按照utf-8编码统一下传,而控件根据服务器端utf-8的码流通过mulitiBytesToWideChar函数将按照unicode重整一次,然后按照w字符的字符串指针传递给脚本引擎。这时候,由于有w字符串指针确定性的影响,脚本引擎不会按照客户端机器环境进行工作,而会按照确定的unicode去对待,将一切都纳入确定性的框架内,这样这个国际化的程序,才能行的更远!
 
确定性,字符集乱码,码流,
 

你可能感兴趣的:(c&c++技术,脚本,服务器,引擎,框架,javascript,工作)