2022年,一则娱乐新闻冲上了热搜,但网友们很快发现,这里的“⼊”并不是我们常用的中文“入”,而是热心人为了降热度用的替换符号,给我们玩了一个花招。

这只是有关电脑文字的无数小故事之一。

在过去的日子里,你见过跟别的字格格不入的孤寡文字,打开过全是 “锟斤拷” 的txt小说,全是框框的游戏对话,点击过长得跟真网址一模一样的钓鱼网站,甚至有一个连派出所也登记不了的名字......

所有这一切,都跟电脑显示文字的原理有关。在这期视频里,我们会带你入门中文显示,了解乱码、孤寡文字和钓鱼网站背后的有趣故事。

话不多说,开始吧!

视频

↓↓ 看完这个视频就知道了 ↓↓

 锟斤拷�⊠是怎样炼成的——中文显示“⼊”门指南|图文
打开网易新闻 查看更多视频
锟斤拷�⊠是怎样炼成的——中文显示“⼊”门指南|图文

↑↑ 信我,真的超级好看 ↑↑

图文版

电脑显示文字,涉及到三个重要的概念:字符字符集字符编码

一个汉字、一个拉丁字母、一个数字、世界上各种语言里的“字”和“标点符号”……都属于“字符”。一堆字符组成的集合,叫做“字符集”。

人类世界有海量的字符,它们原本都写在纸上,甚至刻在石头上。而所有这些字符,计算机......一个都不认识

你肯定知道,计算机只认二进制,只能以比特的形式记录“0”和“1”。为了让计算机“识字”,我们就需要把这些字符用0和1表示出来。把字符转换成0和1的规则,叫做“字符编码”。

那么,怎么给字符编码,把它们变成0和1呢?

很简单:我们可以选定一个字符集,让字符们“排排坐”,再把“座位序号”转换成二进制——这个“座位序号”叫做“码位”,座位的总数叫做“码空间”。码空间越大,字符集就越大。

比如世界上如果只有“柴”“知”“道”这三个字的话,那我们就可以把“柴”编码00,“知”编码为01,“道”编码为10。这样计算机一看到这些编码,就知道要显示哪个字了。

在现实世界中,计算机存储数据的基本单位是“字节”,也就是Byte。一个字节,由8个二进制位组成,也就是8个比特(bit)。每个比特有0和1两种状态,8个比特一共有2^8个,也就是256种不同的状态。

所以如果只用一个字节长度来编码字符,那么这个字符集就能容纳256个字符。

听起来很少对不对?但对于英文来说已经够了,反正他们一共只有 6个英文字母嘛~

所以在上世纪60年代,美国人先搞出了“美国信息交换标准代码”,简称ASCII。ASCII总共收录了128个字符,包括大小写拉丁字母、数字、常用标点,以及像ESC、换行这种看不见的控制字符。

到此为止,事情都很简单:无非就是给这128个字符按照顺序排号,再把序号转换为二进制数字。需要显示的时候,从计算机存储的 ASCII 字符集中按编号调用字符,就能在屏幕上显示出来。

一个字符集,对应一个编码规则,不会出错,一切都很清晰、简单、完美。

但所有的完美都是易碎的。这世界上远远不止英文一种语言,当各国都要跑步进入信息化社会的时候,文字显示的“乱纪元”就开启了。

刚才说过,用一个字节编码字符,最多能容纳256个码位。英语一共才那么点字符256个码位用完都还剩一半。所以西欧一些国家,就搞了“扩展美国信息交换标准代码”,EASCII,也就是用剩下的这128个空位,来表示其他的字符:比如上方有注音符号的法语字母,西班牙语里的特殊标点,数学上常用的α、β等希腊字母,以及一大堆特殊符号等等。

这时候,问题就已经开始冒头了:

各国搞的EASCII字符集和编码,后面128个字符都不太一样,一共搞出了200多种EASCII,互不兼容。就算是同样一串二进制数,在不同的EASCII中对应的字符也不同。所以同一份文本哪怕放到不同语言的计算机中打开,都可能会出现“乱码”。

这还算好的。因为当信息高速公路修到中、日、韩等国家和地区时,就要面临一个更复杂的问题:汉字

汉字的历史源远流长,总数量那可太多了。我国1980年公布的《GB 2312-80 信息交换用汉字编码字符集 基本集》,就包含了6763个常用简体汉字,以及一些标点、符号、数字、拉丁字母等。

那很显然, 1个字节长度最多只能编码256个字符,对汉字来说根本不够用。所以GB 2312用两个字节长度,来编码一个字符,这样理论上就可以容纳2^16个,也就是65536个字符。现在输入法里的全角标点符号就是用两个字节编码的,而半角标点符号,就是用一个字节编码的。

不过,GB 2312-80字符集里这六千多个汉字,只是最最常用的汉字,其实根本不够用,比如像“喆”“頫”“旻”“祎”这些人名中的常见字甚至都不包括在内。

那字符集里没有的那个字怎么办呢?那就打不出来。

所以在过去,如果你叫“张”的话,那对不起,办不了证,只能改名了。

在2009年,广州番禹的一个村子,就因为村名中有一个电脑打不出来的生僻字,不得已更名,这才为全村村民办下来了第二代居民身份证。

而在今天,更新的字符集已经包含了这些生僻字。但虽然能打出来,却也经常显得“孤寡”。因为绝大多数简体汉字字体,都还是只适配了GB 2312里的这六千多个常用汉字。比如最常见的公文字体之一「仿宋 GB2312」,意思就是说我只设计了GB 2312字符集中的字符。

那如果你的名字生僻一点,不在这个字符集中,那么计算机要么调用其他字体来显示,要么直接给你显示成个框框。总之就是显得格格不⼊

这还不算完。因为汉字有简体,有繁体,而且虽然起源于中国,但远不止中国一家用。日本用日本汉字、韩国用朝鲜汉字,大家都搞出了自己的字符集和编码规则,都优先考虑本地人使用方便,相互之间的兼容性很差

后来微软被逼急了,就根据各地字符集和字符编码,自己扩展了GB 2312字符集,加入了一些繁体汉字,这份扩展的字符集后来成为了“汉字内码扩展规范 GBK”,这里的 K 就是“扩展”的意思。

不过,GBK并不是国家标准,只是一个普通的技术规范,这种缝缝补补又三年的打补丁操作,又成为了后续一大堆乱码的来源之一。你继续往后看就知道了~

总而言之,随着计算机在全球迅速普及,各种字符编码已经乱得不能再乱了。人类早晚要解决这个问题,而摆在面前的方案有两种:

第一……整个世界清静了,让一切归零从头再来,“书同文,车同轨”。

当然,这个方案的代价稍微有那么亿丢丢大了。所以人类略微思考了一下,还是选择了第二种比较温和的方案:

我们搞一个超~~级大的字符集,囊括人类世界所有的字符,然后编码出来,供全世界使用,这不就搞定了?

这个超级大的字符集,人类文字编码届的巴别塔,就是Unicode,中文名叫“统一码”或“万国码”。

Unicode野心很大,它一上来就收录了25种文字,两万八千多个字符,其中就包含了GB 2312中的六千七百多个简体字。

为了收纳这么多字符,Unicode决定以书写系统为标准来分类和收录字符。

这什么意思呢?像英语、德语、法语、西班牙语……都属于同一套「书写系统」——拉丁字母。虽然拉丁字母里的“o”,和西里尔字母“о”,以及希腊字母“ο”,长得几乎一样,但既然属于三个不同的书写系统,而且过去各地都已经搞出了相应的字符编码,为了兼容性,就需要安排三个不同的码位

至于我们中国的简体字繁体字,以及日本汉字朝鲜汉字等,则被归纳为「中日韩统一表意文字」。由于一些汉字在各地都用,只是长得略微有点区别,为了节省码位,Unicode就让这些字共用一个码位

Unicode 的这种分类收录方式,愿望是好的,但坑也是挖了不少的。

比如这串网址,它看上去是苹果公司的官网,但这个字母,根本不是拉丁字母 a,而是西里尔字母。所以用这种方法,就可以轻而易举制作出钓鱼网站,诱骗你的帐号和密码。

在汉字世界,也有人利用Unicode玩出了类似的花招: Unicode中,收录了214个康熙部首。你看,它们跟普通汉字长得几乎一模一样

当初 Unicode 收录这些康熙部首,是为了方便词典和输入法能给汉字排序,并跟中国台湾的「中文标准交换码」兼容。当年就有人担心,这些部首跟常用汉字长得太像,可能会出显示问题。于是 Unicode 把它们列为了“兼容字符”,这样在正常情况下,用户很难输入这些部首

但人类的聪明才智是用不完的。视频开头的这手花活,就是利用康熙部首的“⼊”,替换了正常的“入”。

当然,绝大多数中文字体都没有闲工夫去适配这些康熙部首。所以你换个字体试一下,就会发现它露馅了。

在诞生后的这些年里,Unicode一直在不断地更新、扩展,尽力容纳人类世界的所有字符。如今它已经有了1114112个码位,并平均划分成17个平面,每个平面都有65536个码位。

在单个平面上,再根据具体的用途划分出“区块”。“区块”相当于把同类字符放到一起,以方便检索和补充。

GB 2312中的六千七百多个常用的简体字,一大堆你不认识的汉字,陕西biángbiáng面的biáng,可能无法正常显示),你用的emoji 表情,都已经被收纳进了 Unicode 字符集中。

其中甚至还有为各个国家、地区、甚至企业准备的“私用区”,可以供大家自定义使用。像苹果就把自己的logo 放进了私用区,只有用macOS、iOS等苹果操作系统的朋友才能看见这个字符,而Windows和Android拒绝显示。

《星际迷航》的粉丝们,还把克林贡文字放进了私用区,只要你装了这些相关的软件和字体,就能输入和显示克林贡语。

如今,大一统的Unicode已经成为了计算机科学领域最常用的字符集。但是,文字显示的“乱纪元”并没有随着Unicode的出现而结束......

Unicode 虽然号称“统一码”,但一统江湖哪有这么简单?毕竟各个国家都有各个国家的具体情况啊。

作为一个超级庞大的字符集,Unicode也需要让这些海量的字符“排排坐”,然后进行编码,转换成二进制的0和1。曾经大多数字符集,都只有一种编码方式。而超级无敌大的Unicode字符集,有很多种编码方式,你在一些文档软件里看到的UTF-8、UTF-16、UTF-32等,都是把Unicode字符集中的字符,转换成二进制信息的编码方式。

目前最常用的,是UTF-8编码。我国一些政府机关进行信息化建设时,也会要求文档应使用UTF-8编码存储。

编码很重要。因为即使是同一串二进制数字,在不同的字符集和编码方式下,也会对应不同的字符。所以如果用错误的编码打开文本,乱码就来了。

你还记得之前讲到的,微软为了容纳各种汉字搞出来的GBK字符集和编码吧?在中文世界里,GBK和Unicode,都有很多的使用者

当GBK与Unicode激情碰撞之后,噩梦般的上古神器——“锟斤拷”就诞生了。

你看啊,当你写出这段文字,点击保存,此时它们就被按照GBK编码存储成了这串二进制数字。

然后你把这份文档发给了心爱的人,她用最常见的UTF-8编码打开。此时软件就懵逼了,因为它会发现这些东西根本无法正常显示。

此时,Unicode 就会用这个替换符号�,来展示所有无法正确显示的字符。

这时她也懵逼了~心想算了,保存一下发给室友让她帮忙打开吧。在她点击保存的那一瞬间,文档中所有的�字符,就被根据UTF-8编码,编码为了0xEF BF BD

而收到这份文件的大冤种室友,再次使用GBK编码打开了这份文档。此时根据 GBK 编码规则,如果有连续两个问号,那么EFBFBDEFBFBD这三个码位对应的,正是“锟斤拷”三个字。

也就是说,连续两个问号,就对应了一个“锟斤拷”,一串问号,就对应了满屏的“锟斤拷”。

经过这套行云流水的操作,你的爱已经完全找不回来了,坍缩成了无穷无尽的“锟斤拷”

在中文世界里,GBK编码和Unicode都非常常见,比如Win 7、Win 8以及Win 10较早期的中文版中,它们自带的记事本用的就是所谓的ANSI编码。ANSI在不同语言系统中所代指的实际编码不同,在简体中文系统中,它就是GBK编码

而Mac上的“文本编辑”,以及一大堆其他软件,默认用的是UTF-8编码。所以你一不小心,就能搞出一份乱码文件。

以至于像Word这样的软件都学刁了,还经常会在打开时让你玩猜猜看,请你猜一猜,这份文档到底是什么编码呀~

而“锟斤拷”还不是最离谱的。我们可以给你展示一个更灵异的现象:

没错,你拿一台安装了Win 7的电脑,也可以轻松地重现这个bug。当你敲下“联通”两个字时,它就被记事本按照默认的 GBK 编码,编成了这串二进制数字。

而当你再次打开它时,记事本会觉得,哎?这串二进制数字的开头,长得跟UTF-8编码的文件很像嘛!这题我会!于是就用UTF-8编码打开了它,显示出乱码。这就是灵异事件的由来。

好了,这个关于文字显示和乱码的长长的故事,总算可以告一段落了。

其实现在,乱码的情况已经比之前少了很多。随着Unicode这座现代的巴别塔越盖越高,采用它的软件也越来越多,如今新版的Windows系统已经把记事本的默认编码改成了UTF-8 。很多常用软件也做了一些应对,尽量避免乱码。

但在地球各地,还存在很多老设备,老软件,你不知道里面装着什么样的字符集,用着哪些编码。每一次乱码,都是过去与现在,此处和彼处的隔空对撞,你就当它们是错综复杂的计算机技术发展史,给我们放的一朵朵大烟花吧~

当然,你如果特别烦乱码,觉得所有现有的方案都不够好........那其实也有别的解决方案,你应该记得吧,我们刚不是说了吗?

这期视频做的真的很辛苦,我们努力用最简明的方式,来讲清跟字符集、编码和乱码有关的问题。

因为内容很长,所以我们把整个文字版脚本,包括注释等,都放在了这份文档里,你可以慢慢阅读。受限于篇幅和整体逻辑,有一些有意思的知识点或者小故事,我们没法儿放进视频里,所以一并写到了这份文档中。有兴趣的话,可以关注我们,在后台回复“字编码”,就可以获得这份文档。