本帖最后由 vitrel 于 2021-12-10 08:03 编辑
(首先非常抱歉。本贴要讨论的是乱码,但奇怪的是,只要贴子的标题或正文中出现乱码字符,后面的内容就无法显示。可能是论坛不支持吧。没办法下之,只能将这些乱码字符全部去掉,部分内容改用图片代替,表达上肯定会略显别扭,望多多体谅!)
电脑用久了,偶尔会碰到如下表的这类“乱码”(有网友笑称其为“火星文”)。这类乱码是如何来的呢?如何才能转换回我们能阅读的编码呢?本贴就为大家简单介绍一下。 (特别说明:1、本贴所说的编码,特指字符串编码。2、乱码的种类多种多样,本贴所讨论的仅是下表这一类乱码。)
一、预备知识(对字符编码有一定认识的网友,可略过此节) 1、计算机在发明之初,仅有128个(扩展后也仅有256个)字符的ASCII编码便足够为英语语种的美国人服务。 2、世界各地有不同的语种,显然,仅有256个字符的ASCII编码并不适合计算机在全世界推广。于是随着计算机的全球推广,为了能在电脑上显示世界各地不同的语言字符,各种字符编码应运而生。 3、对于Windows系统 ,在中国大陆地区所用的简体中文版中,用的是GB2312编码(后续升级的还有GBK、GB18030编码);而对于香港、台湾地区所用的繁体中文版中,用的是Big5编码。 4、正所谓“分久必合,合久必分”,当年为在全球推广计算机,世界各地创建了不同的字符编码。这些编码多了,编码间的转换又是件令人头疼的事,反过来又阻碍了信息的传播。于是乎,Unicode编码(又称为统一码、万国码、单一码)又应运而生了,从名字就知道,这种Unicode编码集合了全世界所有语言的字符编码,算是潮流发展的一种趋势。 5、Unicode编码虽好,兼容了全世界的语言。但它为了让全世界的字符兼容,特意规定了用两个字节来统一表示世界上所有的字符。在这个标准中,明明可以只有一个字节来表示的ASCII里的英文、数字字符(被迫)也用两个字节来统一表示。这种方案非常浪费存储空间,显然不适合字符串在网络中传输。于是UTF-8编码应运而生。你可以把UTF-8理解为一种针对Unicode的可变长度字符编码,多用于网络传输。 6、对于简体中文版的Windows,使用的是GB2312编码。任何字符串(不管是何种编码),系统都会把它转换成GB2312编码再显示出来。若转换错误,显示的就会是乱码。 7、在VBA中,使用的是Unicode编码。与上同理,任何字符串(不管是何种编码),VBA都会把它转换成Unicode编码再显示出来。若转换错误,显示的就会是乱码。 8、(划重点)有3种字符编码,是我们经常会接触到的,它们是:GB2312、Unicode、UTF-8。它们的各自字符编码举例如下: 9、为了区分各种编码,往往会在在整条字符串的开头会增加2~3个(与字符内容无关的)字节,用特定的字符作为标示。这增加的标识字符俗称“BOM头”。凡是接收到一串字符串,就可以简单地从字符串的BOM头判断出这是何种编码的字符串,为下一步的编码转换工作提供基础。
二、“涓xxx”这类乱码的由来 尽管简体中文Windows用的是GB2312编码,但不可否认,UTF-8编码越来越常见了。下面我举两个例子,说明“涓xxx”这类乱码的由来:
<例1>系统接收到一个字符串(二进制编码为EF BB BF E4 B8 80 E4 BA 8C E4B8 89),这个字符串分为两部分。前面的“EF BB BF”是UTF-8编码的BOM头,后面的“E4 B8 80 E4 BA 8C E4 B8 89”是“一二三”的UTF-8编码。因此系统很容易就从BOM头判断出这是一串UTF-8编码的字符串。上面的预备知识中已经提过,在VBA中,任何编码的字符串都必须转换成Unicode编码才能显示出来。上述字符串也不例外,VBA会把它从UTF-8编码自动转换为Unicode编码,然后正常地显示出“一二三”来。
<例2>与上例相仿,系统接收到一个字符串(二进制编码为E4 B8 80 E4 BA 8C E4 B8 89,这是“一二三”的UTF-8编码)。由于这个UTF-8编码的字符串缺少了BOM头,系统无法准确判断其编码类型,以至于在VBA中,系统将其误判为GB2312编码。于是乎,VBA便以“GB2312转Unicode”的方式,把该字符串自动转换成一串错误的Unicode编码出来,然后便会错误地显示出“涓xxx”来。由于我们看不明它的真实意思,便把它叫做“乱码”。 在例2中有两点要说明一下: 1、明明是UTF-8字符串,为何没有BOM头?原因是BOM头并非必要的,有很多情况下,应该有BOM头的字符串都不带BOM头。 2、为什么会误判为GB2312编码而不是别的编码?原因一方面是GB2312编码确实是没有BOM头的。但可能你会说,没有BOM头的未必就一定就是GB2312编码,确实没错,所有还有另外一个主要原因,就是(上面提到的)GB2312编码是简体中文Windows默认的编码,是最最最普遍的存在。既然不知道字符串的编码,那就惯性地把它当成是GB2312编码好了。而实践证明,这样做绝大情况下是正确的。可惜的是,在本例中偏偏是错误的,这种惯性还是乱码的根源。
当我们了解了“涓xxx”这类“乱码”的来源(产生的原因)以后,我们反过来讨论一下这类编码的名字。我查过网上,这类乱码并没有“官方”的名字(它的出现就是个错误,它本不该存在)。有网友把这类乱码归类为UTF-8编码,我认为这样是不妥的,因为它与真正的UTF-8编码有本质上的区别。但它确实是由UTF-8编码“变种”而来,如果硬要给它安个与UTF-8有关的名字,我个人认为,把它叫做“另类UTF-8编码”或许更贴切一些。
三、乱码还原 既然知道乱码的由来,那么转换(还原)的方法就简单了,无非就是个逆转换的过程。在VBA中,字符串的转换方法有很多,但最简单的就是采用ADODB.Stream对象来处理各种编码转换。 ADODB.Stream是ADO的Stream对象,提供存取二进制数据或者文本流,从而实现对流的读、写和管理等操作。如想深入了解ADO的Stream对象,可参考《 ADODB.Stream 对象详解》。 本贴提供的实例文件中,我收集了4种方法可把这类“另类UTF-8编码”还原。不想贪功,代码都写明了出处,我略为优化了一下,更增加了详细的备注说明,以方便大家参考。
以下提供几个这种“另类UTF-8编码”的“素材”网址,以供大家测试: https://club.excelhome.net/thread-1608733-1-1.html https://www.zhihu.com/question/390317747 https://www.jianshu.com/p/5797e8090348 https://blog.csdn.net/site008/article/details/77981679
|