作者:wzy
wzy
covers
内容简介:计算机在显示字符的路上的磕磕绊绊
2023/02/28 19:33

锟斤拷是怎样炼成的

在此感谢B站UP主柴知道

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

这只是有关电脑文字的无数小故事之一。在过去的日子里,你见过跟别的字格格不入的孤寡文字,打开过全是“锟 (kūn) 斤拷”的txt小说,全是框框的游戏对话,点击过长得跟真网址一模一样的钓鱼网站,甚至有一个连派出所也登记不了的名字......

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

话不多说,开始吧!

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

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

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

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

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

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

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

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

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

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

所以在上世纪 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 字符集里这六千多个汉字,只是最最常用的汉字,其实根本不够用,比如像“喆”,“頫(fǔ)”,“旻(mín)”,“祎(yī)”这些人名中的常见字甚至都不包括在内。

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

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

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

而在今天,更新的字符集已经包含了这些生僻字。但虽然能打出来,却也经常显得“孤寡”。

因为绝大多数简体汉字字体,都还是只适配了 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 中的六千七百多个常用的简体字,一大堆你不认识的汉字,陕西biangbiang面的biang,你用的 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 激情碰撞之后,噩梦般的上古神器——“锟(kūn)斤拷”就诞生了。

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

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

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

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

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

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

在中文世界里,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 。很多常用软件也做了一些应对,尽量避免乱码。

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

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

备注

  1. 关于“𬀩”字 音 wěi,Unicode 码位 U+2C029,位于 SIP,“中日韩统一表意文字扩展区 E”,来自《现在汉语词典》。

  2. 关于“táng 闾巷” 的“táng”字 如下图。Unicode 码位 U+28D88,位于“中日韩统一表意文字扩展区 B”,有“高门”之意。 [图片]

  3. 关于 Unicode 通常我们说 Unicode 都是指“Unicode 标准”,英文为 Unicode Standard,它是由 Unicode 联盟制定的。Unicode 联盟是民间组织,成员为大型商业公司,比如微软、苹果、华为等,以及相关领域的专家和学者。因此,由 Unicode 联盟制定出来的 Unicode 标准在政治层面实质上并不具备强制性。 各国、地区的官方标准则是根据 ISO/IEC 10646 来制定的。ISO/IEC 10646 跟 Unicode 标准区别不大,码位完全一致,二者几乎可以划等号,只是面向的对象不同。

  4. ASCII 与 EASCII ASCII 是只有 128 个字符,8 位是能表示 256 个字符的。所以 ASCII 二进制的首位默认是 0。后来 EASCII 的首位都是 1。 ASCII 拉丁字母部分码位设计得特别巧妙。二进制情况下,大小写转换非常方便,只需看(从右往左)第六位数字即可,0 是大写,1 是小写。比如,“0100 0001”是 A,“0110 0001”是 a。

  5. GB 2312-80 是否为国家强制标准? 《GB 2312-80 信息交换用汉字编码字符集 基本集》(GB 2312-80)于 1980 年公布,并于 1981 年 5 月 1 日正式实施,当时为国家强制标准。 根据我国国家标准公告(2017 年第 7 号)和强制性标准整合精简结论,这一标准自 2017 年 3 月 23 日起转化为推荐性标准。现应为“GB/T 2312-80”

  6. 什么是“书写系统”? 在 Unicode 标准中,书写系统的定义有两个。在「6.1 Writing Systems」开头,给出了两个定义: The term writing system has two mutually exclusive meanings in this standard. As used in this section, “writing system” refers to a way that families of scripts may be classified by how they represent the sounds or words of human language. For example, the writing system of the Latin script is alphabetic. In other places in the standard, “writing system” refers to the way a particular language is written. For example, the modern Japanese writing sys- tem uses four scripts: Han ideographs, Hiragana, Katakana and Latin (Romaji). 简单来说,第一种是整个 6.1 章节中用的,大概是说「表音文字」「表意文字」这种划分方式。 第二种是标准其他地方这个术语的定义,就是正文中用的「一种特定语言的书写方式」。比如,现代日语有四种书写方式:汉字、平假名、片假名和拉丁文。

  7. Emoji 冷知识 Emoji 最早只是移动运营商,以及聊天软件们自己开发的。后来随着使用人数越来越多、范围越来越广,微软、苹果、谷歌这些跨国巨头们,向 Unicode 提案,将 emoji 正式加入 Unicode 字符集中,安排在 SMP 中。 值得一提的是,由于 Unicode 只规定 emoji 的含义,不管它们具体长啥样,所以决定你看到的 emoji 长啥样的,是字体。不同操作系统和平台上,使用的 emoji 字体不同,所以你看到的表情符号也不一样。比如, Mac、iPhone上的手机、手表、键盘、鼠标等 emoji 长得都是自家产品的样子,而在 Windows 上就朴实无华得多。 在 Unicode 14.0 中,总共收录了几千个 emoji,包括这些你熟悉的表情,以及不同肤色、发色的人物,各国家的地区的旗帜,各种性别组成的家庭等等。照这个趋势,也不知道 Unicode 未来会不会再收录五口之家、六口之家的 emoji 有趣的是,其实这些家庭无论怎么加,其实并不会单独占用 Unicode 码位,它们是用已经存在的 Emoji 组合起来的。比如这个“凑成一个‘好’字”的四口之家👨👩👧👦,就是由男人👨、女人👩、女孩👧、男孩👦这四个单独的 emoji“拼”起来的。 [图片] 再比如各种旗帜,目前 Unicode 共由两百六十多面国家和地区的旗帜,但其实总共只占用了几十个码位。Unicode 这是因为 Unicode 中有一组专门用于表示旗帜的特殊拉丁字符,用来表示国家的英文缩写。比如“中国”的英文缩写为“CN”,就用 U+1F1E8、U+1F1F3 这两个特殊字母组合起来,代表中国国旗,然后再由字体具体实现这面国旗长什么样。

  8. Unicode 平面 在 Unicode 目前的 17 个平面中,只用到了 7 个平面,其他 10 个平面还没有规划。 其中 GB 2312 中的六千七百多个简体字,位于基本多文种平面 BMP 。这个平面收录的是全人类最常用的字符,历史最为悠久,所以计算机系统、软件、字体等对 BMP 平面内的字符支持最为完整。 所以,BMP 平面上每一个码位都十分珍贵,只有特别重要的字符才能得到这个平面的码位。比如中国就在 2018 年往里面加入了三个新的化学元素用字。 目前 BMP 平面已经基本被塞满,只剩下 16 个码位空余。 部分翻译对照

  • 字符 - Character
  • 字符集 - Character Set
  • 字符编码 - Character Encoding
  • 字体 - Font
  • 字形 - Glyph
  • 码位 - Code Point
  • 码空间 – Code Space
  • 乱码 - Mojibake
  • 替换符号 - Replacement Character
参考文献:https://u0y2lvcc3a.feishu.cn/docx/doxcnQEbKZNVew6qrRmzFh9oiTd
文献视频:https://www.bilibili.com/video/BV1cB4y177QR/

评论区

登录之后才能评论Scratch作品哦
鸡仔之巅1 年前

你跑题了吧……

北柠Tracy1 年前

牛逼牛逼

一只Fresh1 年前

《长篇大论》(不懂but震惊)

wzy1 年前
@一只Fresh

看视频就知道了

wzy1 年前
@一只Fresh

https://www.bilibili.com/video/BV1cB4y177QR/