好像第一次遇到跟字符集有关的问题大概应该是在7年前,第一次写java,总是会出现编码转换的问题,动不动就乱码,基本上,本着实用主义的态度,以盲人
摸象的手法,总算是能够解决问题的。这些年来,不停的会遇到编码方面的问题,随着每一次解决问题,都感觉多揭开了一点笼罩在这一堆乱七八糟的东西上面的迷
雾,然而,直到去年年中,我仍然没有完全搞明白这堆乱七八糟的名词和概念之间,究竟是怎样的关系。
去年年中开始的项目,需要用c++来处理文档,不可避免的遇到了编码转换的问题,在用c++处理的时候,我不得不仔细的探究在不同的编码转换的时
候究竟发生了什么事情,终于,总算是搞明白了这些东西。下面,我会试着解释一下这些概念本身以及他们之间的关系,部分解释来自维基百科或者msdn,版权
不属于我。
ANSI/ASCII : 由美国国家标准委员会指定的是基于拉丁字母的一套电脑编码系统。它主要用于显示现代英语和其他西欧语言。它是现今最通用的单字节编码系统,并等同于国际标准ISO 646。(from wiki)
MBCS : 多字节字符集,是一种替代 Unicode
以支持无法用单字节表示的字符集(如日文和中文)的方法。为国际市场编程时应考虑使用 Unicode 或
MBCS,或使程序能够通过更改开关来生成支持两种字符集之一的程序。最常见的 MBCS 实现是双字节字符集 (DBCS)。一般来说,Visual
C++(尤其是 MFC)完全支持 DBCS。(from msdn)
UNICODE : 是业界的一种标准,它可以使电脑得以呈现世界上数十种的文字系统。Unicode 是基于通用字元集(Universal
Character Set)的标准来发展,并且同时也以书本的形式(The Unicode
Standard,目前第五版由Addison-Wesley Professional出版,ISBN-10:
0321480910)对外发表。Unicode 包含了超过十万个字元(在西元 2005 年, Unicode
的第十万个字元被采纳且认可成为标准之一)、一组可用以作为视觉参考的代码图表、一套编码方法与一组标准字元编码、一套包含了上标字、下标字等字元特性的
列举等。(from wiki)
UTF-8 : 英文全称为8-bit UCS/Unicode Transformation Format,是针对Unicode
的一种可变长度字元编码。从名称可以看出,UTF-8是专为UCS/Unicode设计的传输格式。它可以用来表示 Unicode
标准中的任何字元,而且其编码串流中的第一个位元组仍与 ASCII 兼容,令原来处理 ASCII
字符的软件无需或只作少量改动后,便可继续使用。因此,它逐渐成为电子邮件、网页及其他储存或传送文字的应用中,优先采用的编码。(from
wiki)
基本的名词解释完了,现在来仔细的解释一下Charset/Encoding(字符集/编码)。Charset很容易和Encoding搞混,也
是刚开始接触字符编码问题是最容易被晕掉的概念。字符集的概念,实际上,包含两个方面,一个,是字符的集合,即所谓的Charset,一个是编码方案,也
就是所谓的Encoding。所谓字符的集合,意即一个字符集,定义了它所包含的所有符号,这实际上正是字符集名字的真正含义。也就是说,狭义上的字符
集,并不包含编码方案,它仅仅是定义了哪些符号属于这个字符集。但是,通常来说,一个字符集并不仅仅定义字符集合,同时,它还为每个符号定义一个二进制编
码,所以,当我们提到GB2312的时候,我们并不仅仅是指GB2312字符集,同时,也指明了编码方案是GB2312,即Charset=
GB2312,Encoding=GB2312,这说明,我们的文档中不包含GB2312以外的字符,而它们的二进制编码采用GB2312规定的编码方
式。简单的情况的确如此,字符集等于编码,编码等于字符集。
但是,通常把我们搞晕的,正是一个例外,Unicode。Unicode字符集本身定义的编码方案通常称为UCS-2,或者一个更通用的名字,
UTF-16。然而,由于UTF-16不能和现行的基于ascii的编码方案兼容,比较重点的问题在于0x0,在基于ascii的编码方案中,一个8位的
0x0总是表示一个字符串的结束的,而UTF-16则不然,它的一个字符,完全有可能在高8位或者低8位上等于0x0,这会导致很多应用程序错误,尤其是
在网络传输协议当中可能导致大量的字符串错误截断。于是,有了UTF-8,UTF-8提供了一个跟ascii兼容的unicode字符集编码方案。网络上
常见的说法说UTF-8是1到3位变长编码,这是错误的,UTF-8是1到6位变长编码,3位的说法来源于大多数常用汉字被包括在3位编码的范畴以内,而
另外,从现行的Unicode规范来讲,UTF-8实际上是1到4位的编码,因为再加上两位编码所扩展的范围现在Unicode还没有定义任何字符。
UTF-8的编码方案首先保证跟127个标准ascii字符兼容,也就是说,在UTF-8方案下,Unicode的0x000000–0x00007F范
围的字符被表达为0x0-0x7F的一个字节的二进制编码。其次,UTF-8保证,所有0x7F以上的字符,在被转译成多字节字符时,每个字节的最高位一
定为1,这实际上也是大多数MBCS方案的基本原则,否则应用程序没法识别多字节字符的字节组合方式或者出现错误的0x0。问题在于,一般的DBCS双字
节方案可以简单的根据高位是否为1而判定单字节还是双字节,而UTF-8是变长的,应用程序需要知道如何组合连续的字节数据,按照UTF-8的规定,除了
最高的一个字节外,其余的所有字节均以10开头,而最高字节的开头,110表示连续2位,1110表示连续3位,11110表示连续4位。(一个具体字符
的UTF-8编码值根据一个简单的对应算法从UTF-16得到,这里就不详细讲述,请自行google)。因此,我们必须明确一个概念,UTF-8是
unicode字符集的一个编码方案,当我们在说到UTF-8字符和Unicode字符的时候,在某些情况下,它们在逻辑上是等价的,但是,他们并不是同
一个东西,因为Unicode字符在二进制上还有一个选择就是原生的UTF-16编码。
总结一下,Unicode字符集规定的标准编码方案是UCS-2(UTF-16),用两个字节表示一个Unicode字符,而事实上,UCS-4
(UTF-32)也已经被提出了,用4个字节表示一个Unicode字符,然后,一个常用的Unicode编码方案—UTF-8,它用1到4(6)位的变
长字节来表示一个Unicode字符,并可以从一个简单的转换算法从UTF-16直接得到。这三个编码方案(Encoding)都对应于Unicode字
符集(Charset)。
然后,需要解释一下Codepage-代码页,codepage实际上是一张表,通常的codepage是一个从unicode到其他mbcs的
转换索引表,比如windows上常用的MS936代码页,实际上就是GB2312到unicode的转换表,我们知道,windows是完全基于
unicode的,MS的应用程序也大多是基于unicode开发的,他们对GB2312的支持,正是来源于codpage932,通过cp932的转
换,应用程序可以在unicode和gb2312之间来回转换。需要多一句嘴的是关于日文编码,IBM和微软都提供了几个工业上常用的日文编码的代码页,
比如对于shift-jis,IBM的代码页是CCSID943,这也是java在转换时使用的代码页,而MS的代码页是MS936,他们两者都是针对
shift-jis的代码页,算是两个并行的工业标准,在某些字符上转换结果并不一致,这可能会导致应用程序错误,比如我遇到的典型问题是通过java程
序将shift-jis数据转换为unicode后传输给VC编写的程序再转换为shift-jis,由于在两次转换中使用了不兼容的代码页,导致数据错
误。这并没有什么特别的解决办法,只能是查找特殊字符列表作特殊处理。
另外一个问题,就是所谓的基于unicode的应用程序,在应用程序内部字符串究竟以什么形式表达,一般来说,是以UCS-2也就是UTF-16
的二进制形式来表达的,UTF-8一般只是作为数据传输格式和文档保存格式。具体一点,对于java代码,javac编译程序在你没有指定源文件编码的情
况下,总是将其认为是本地缺省编码,比如在简体中文windows上会被认识为GB2312,而在日文windows上会被识别为shift-jis,然
后实际上,在编译的时候,gb或者jis字符都会被转换成对应的UCS-2二进制值。而对于C++程序,当你简单的用 ”中”
这样的引号引用的形式的时候,编译器会简单的将其识别为本地编码并且在编译后的二进制代码中被表达为本地编码的二进制值(我不知道c++编译器能否指定源
文件编码。。。我不太熟悉c++),但是,如果你用 L”中”
这样的标准c++的unicode字符定义方式来定义字符时,将会发生和javac编译程序一样的事情,编译程序会主动的将字符正确的以本地编码识别并转
换成UCS-2值保存为编译后的二进制代码。C++程序中,如果以L宏定义字符串,可以在程序中直接得到Unicode值,即UTF-16编码值,但在
java中,实际上我们并不能直接得到字符串的二进制值,不过可以通过String的getbytes方法指定UTF-16编码得到。至于各种编码之间的
转换,这里就不赘述了。
最后,解释一下关于font的问题,其实,很多时候我们遇到的乱码并没有出现编码转换错误,只是由于应用程序指定的字体没有包含对应的字符图像而
已,这种情况,通常我们可以看到有部分字符是可以正常显示的。Font文件实际上也是一个索引文件,一个encoding索引加上位图。现在的字体文件通
常包含两个编码索引,一个unicode,一个该字体对应语言的常用编码,应用程序在显示字符的时候,通过查找对应的索引而得到字符的位图。
分享到:
相关推荐
而在Unicode的众多编码方式中,UTF-8因其变长编码、兼容ASCII、无需额外存储空间等特点,成为互联网上使用最广泛的一种编码方式。 在实际开发中,开发者可能会遇到从GBK转到UTF-8这样的编码问题。这里需要注意的是...
PEP 529: Change Windows filesystem encoding to UTF-8 PEP 528: Change Windows console encoding to UTF-8 PEP 520: Preserving Class Attribute Definition Order PEP 468: Preserving Keyword Argument ...
嵌入式八股文面试题库资料知识宝典-华为的面试试题.zip
训练导控系统设计.pdf
嵌入式八股文面试题库资料知识宝典-网络编程.zip
人脸转正GAN模型的高效压缩.pdf
少儿编程scratch项目源代码文件案例素材-几何冲刺 转瞬即逝.zip
少儿编程scratch项目源代码文件案例素材-鸡蛋.zip
嵌入式系统_USB设备枚举与HID通信_CH559单片机USB主机键盘鼠标复合设备控制_基于CH559单片机的USB主机模式设备枚举与键盘鼠标数据收发系统支持复合设备识别与HID
嵌入式八股文面试题库资料知识宝典-linux常见面试题.zip
面向智慧工地的压力机在线数据的预警应用开发.pdf
基于Unity3D的鱼类运动行为可视化研究.pdf
少儿编程scratch项目源代码文件案例素材-霍格沃茨魔法学校.zip
少儿编程scratch项目源代码文件案例素材-金币冲刺.zip
内容概要:本文深入探讨了HarmonyOS编译构建子系统的作用及其技术细节。作为鸿蒙操作系统背后的关键技术之一,编译构建子系统通过GN和Ninja工具实现了高效的源代码到机器代码的转换,确保了系统的稳定性和性能优化。该系统不仅支持多系统版本构建、芯片厂商定制,还具备强大的调试与维护能力。其高效编译速度、灵活性和可扩展性使其在华为设备和其他智能终端中发挥了重要作用。文章还比较了HarmonyOS编译构建子系统与安卓和iOS编译系统的异同,并展望了其未来的发展趋势和技术演进方向。; 适合人群:对操作系统底层技术感兴趣的开发者、工程师和技术爱好者。; 使用场景及目标:①了解HarmonyOS编译构建子系统的基本概念和工作原理;②掌握其在不同设备上的应用和优化策略;③对比HarmonyOS与安卓、iOS编译系统的差异;④探索其未来发展方向和技术演进路径。; 其他说明:本文详细介绍了HarmonyOS编译构建子系统的架构设计、核心功能和实际应用案例,强调了其在万物互联时代的重要性和潜力。阅读时建议重点关注编译构建子系统的独特优势及其对鸿蒙生态系统的深远影响。
嵌入式八股文面试题库资料知识宝典-奇虎360 2015校园招聘C++研发工程师笔试题.zip
嵌入式八股文面试题库资料知识宝典-腾讯2014校园招聘C语言笔试题(附答案).zip
双种群变异策略改进RWCE算法优化换热网络.pdf
内容概要:本文详细介绍了基于瞬时无功功率理论的三电平有源电力滤波器(APF)仿真研究。主要内容涵盖并联型APF的工作原理、三相三电平NPC结构、谐波检测方法(ipiq)、双闭环控制策略(电压外环+电流内环PI控制)以及SVPWM矢量调制技术。仿真结果显示,在APF投入前后,电网电流THD从21.9%降至3.77%,显著提高了电能质量。 适用人群:从事电力系统研究、电力电子技术开发的专业人士,尤其是对有源电力滤波器及其仿真感兴趣的工程师和技术人员。 使用场景及目标:适用于需要解决电力系统中谐波污染和无功补偿问题的研究项目。目标是通过仿真验证APF的有效性和可行性,优化电力系统的电能质量。 其他说明:文中提到的仿真模型涉及多个关键模块,如三相交流电压模块、非线性负载、信号采集模块、LC滤波器模块等,这些模块的设计和协同工作对于实现良好的谐波抑制和无功补偿至关重要。
内容概要:本文探讨了在工业自动化和物联网交汇背景下,构建OPC DA转MQTT网关软件的需求及其具体实现方法。文中详细介绍了如何利用Python编程语言及相关库(如OpenOPC用于读取OPC DA数据,paho-mqtt用于MQTT消息传递),完成从OPC DA数据解析、格式转换到最终通过MQTT协议发布数据的关键步骤。此外,还讨论了针对不良网络环境下数据传输优化措施以及后续测试验证过程。 适合人群:从事工业自动化系统集成、物联网项目开发的技术人员,特别是那些希望提升跨协议数据交换能力的专业人士。 使用场景及目标:适用于需要在不同通信协议间建立高效稳定的数据通道的应用场合,比如制造业生产线监控、远程设备管理等。主要目的是克服传统有线网络限制,实现在不稳定无线网络条件下仍能保持良好性能的数据传输。 其他说明:文中提供了具体的代码片段帮助理解整个流程,并强调了实际部署过程中可能遇到的问题及解决方案。