0

    科技周刊|锟斤拷?烫烫烫?摸清文本乱码的背后

    2023.08.16 | admin | 124次围观

    鐢辨湀瑕佸ソ濂藉涔犲ぉ澶╁悜涓?

    ����Ҫ�¨²�ѧϰ������

    ”±æœˆè¦å¥½å¥½å­¦ä¹å¤©å¤©å‘上

    ÓÉÔÂÒªºÃºÃѧϰÌìÌìÏòÉÏ

    锟斤拷锟斤拷要锟矫猴拷

    烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫

    你没有看错,上面6行都是乱码。日常生活中,不论是文档处理还是程序设计,我们都会遇到类似的乱码,但这些乱码是怎么形成的?我们真的对乱码束手无策吗?

    其实,类似“锟斤拷”的乱码在生活中经常出现,你甚至可以在一些大企业的官网或是软件界面见到他们......

    你比如说甲骨文官方的Java文档......

    以及随处可见的�

    广大程序员间曾流传过一句打油诗:“手持两把锟斤拷,口中疾呼烫烫烫。”因为乱码问题一直以来非常常见。那么这些乱码的成因是什么呢?

    从编码谈起

    C语言课程中提到过,我们在计算机中能够看到的每个文字,在计算机处理的过程中,都要转成二进制,具体用哪些二进制数字表示哪个符号,这就需要编码。

    我们非常熟悉的ASCLL码就是编码的一种,它解决了计算机显示英文字母的问题,ASCII 码一共规定了128个字符的编码,如空格SPACE是32(二进制00100000),数字0是48(二进制00110000)大写的字母A是65(二进制01000001)。

    但是ASCII码在其他语言的情况下并不适用,比如汉字有10万个字符,所以有了其他的编码方式文件发出去是乱码,而世界的语言有许许多多种,一开始,各个国家与地区都是各自弄各自的编码。例如西欧的ISO-8859-1。

    80年代我国大力发展计算机技术,可是出现的问题是,汉字显示不了。于是GB2312编码横空出世,囊括了六千多个常用汉字。

    随着信息化的发展,GB2312似乎也不满足日常使用了,特别是生僻字。于是在90年代在GB2312的基础上扩展到两万多个汉字的字符编码GBK。

    随着时代的发展,两万多个汉字似乎也是不够用,所以再往后,GB2312编码进化为GB18030编码,扩展到了七万多文字,还包含了少数少民族文字。

    不同编码的弊端

    类似地,其他语种也各自推出了自己的编码,但这个问题只是解决了本国语言和英文。当时面对另外一个场景,就傻眼了:一篇文献中,同时要引用中文、西欧文、拉丁文、小语种的文字呢?

    前文已经告诉大家了:ÓÉÔÂÒªºÃºÃѧϰÌìÌìÏòÉÏ

    这是早期出现的乱码,以这个为例,当我们以ISO8859-1的编码方式读取GBK编码的中文文件发出去是乱码,读出来的是这样。这相当于两组箱子,钥匙和锁是一模一样的,但是箱子里的东西不一样,那最终得到的东西还是不一样。

    编码界大一统

    于是在 20 世纪 80 年代末,大家坐在一起,决定讨论下这个事情,于是 Unicode 统一码联盟成立。并于 1991.10 发布了 Unicode 1.0, 到了 2020.3.10,发布到了 Unicode 13.0。今天 Unicode涵盖了包括了emoji在内的多国语言字符和特殊符号

    Unicode 只是一个符号集,它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储。如果 Unicode 统一规定,每个符号用三个或四个字节表示,那么每个英文字母前都必然有二到三个字节是0,这对于存储来说是极大的浪费。

    所以在存储上,就有了Unicode的三种实现:UTF-8 UTF-16 UTF-32

    新老交替出现的问题

    如果我们想要用 Unicode 编码记录一些文本,特别是一些遗留的老字符集内的文本,但是这些字符在 Unicode 中可能并不存在。于是,Unicode会统一把这些字符记录为 U+FFFD 这个编码,它的UTF-8编码是0xEFBFBD。

    U+FFFD这个编码显示出来长什么样子?

    它长这样:�

    也就是说,当Unicode发现了自己没收录而其他以前没统一的时候其他字符集收录的字时,它都会用�代替这个字。

    在中文系统中,常见的字符编码是 GBK,这个时候,如果没有提前声明,默认按照 GBK编码显示。

    我们知道,一个字节=两个二进制位,比如说0xEFBFBD中EF、BF、BD各自是一个字节。

    而�两个连起来就是0xEFBFBDEFBFBD,而根据GBK编码的双字节要求,上面的6字节0xEFBFBDEFBFBD,就被拆成了3个2字节字符即0xEFBF,0xBDEF 0xBFBD,对应GBK编码里面就是:锟(0xEFBF),斤(0xBDEF),拷(0xBFBD)。

    所以,�是我们以UTF-8的方式读取GBK编码的中文出现的。锟斤拷是我们以UTF-8方式读取GBK编码的中文,然后又用GBK的格式再次读取的时候出现的。

    总而言之,这些乱码都是在不同编码的编写和读取之下出现的,这里列一个表,方便大家迅速地找到乱码的原因:

    名称

    示例

    特点

    产生原因

    古文码

    鐢辨湀瑕佸ソ濂藉涔犲

    不认识的古文加杂日韩文

    以GBK方式读取UTF-8编码的中文

    口字码

    ����Ҫ�¨²�ѧϰ

    大部分为小方块

    以UTF-8的方式读取GBK编码的中文

    符号码

    由月要好好

    大部分为各种符号

    以UTF-8的方式读取GBK编码的中文

    拼音码

    ÓÉÔÂÒªºÃºÃѧÏ

    大部分为头顶带有类似声调的字母

    以ISO8859-1方式读取GBK编码的中文

    问句码

    长度为偶数时正确,长度为奇数时最后的字符变为问号

    以GBK方式读取UTF-8编码的中文,又用UTF-8的格式再次读取

    锟拷码

    锟斤拷锟斤拷要锟矫猴拷

    大部分为“锟斤拷”这几个字符

    以UTF-8方式读取GBK编码的中文,又用GBK的格式再次读取

    总之,用什么 [编码规则] 保存为何种形式的二进制段,就用同样的[编码规则]来读取。自然就不会出现乱码了。

    烫烫烫是电脑过热?

    至于“烫烫烫”,肯定是电脑CPU的过热造成的转码紊乱。

    这个乱码会在Visual Studio中出现,Visual Studio会把没有赋值的变量或者内存地址全部填成0xCC,而两个0xCC组成0xCCCC转换成中文就是“烫”了。所以,发现“烫烫烫”刷屏,不是电脑过热报警,而是你的变量没有初始化就使用了。

    小结

    了解了这些原理,相信你未来在遇到中文的编码问题的时候,可以做到“手中有粮,心中不慌”了。

    知其然,还要知其所以然,我们才能在问题发生时有效处理,淡然处之而不至于手忙脚乱。

    往期精彩

    图文:魏子奇

    版权声明

    本文仅代表作者观点。
    本文系作者授权发表,未经许可,不得转载。

    发表评论