打开一本小说全是“锟斤拷”是什么鬼东西?

949 阅读8分钟

版权声明:本人文章仅在掘金平台发布,请勿抄袭搬运,转载请注明作者及原文链接 🦉

阅读提示:网页版带有主题和代码高亮,阅读体验更佳 🍉

记得以前只能用杂牌智能机或者老年机看小说的时候,很多小说一打开就是 “锟斤拷”之类的乱七八糟的文字,完全看不懂,只能重新下。那时候根本不懂这种问题产生的原因,只是以为文件坏了。小时候甚至还出现过有人去登记姓名,结果因为姓氏名字太生僻电脑打不出来,只能改名字的事情......

以上这些奇奇怪怪的文字事件就和我们马上要讲的内容有关,也是所有程序员无法回避的问题:字符集及字符编码。

字符

一个汉字、一个阿拉伯数字、一个 emoji 表情......还有各种特殊符号:*、&、¥、$、# 等都是一个一个的字符。这些字符原本都是各个语言里的文字或者书写符号,不是写在纸上、刻在石头木头上就是装在人的脑袋里。如果大家使用同一种语言符号,那好说,你知我知,可是对于计算机来说,这他喵是什么鬼?汉字个数就几万个,一个中国人都不敢说自己全部认识。所以,这些汉字是怎么录入计算机,计算机如何识别,使用输入法时电脑又怎么知道我们输入的是哪个字呢?

而且作为程序员都知道的一个事情是,计算机只认识 01,也就是二进制数,这个二进制数如何表示出这些奇奇怪怪的字符的呢?

字符编码

聪明的美国人就想到了,毕竟计算机是人家发明的 —— 01 表示的二进制数能被计算机认识,一个 0 或者 1 是一个 bit,8 个 bit 是一个 byte,那这 8 个 01 就有 256 个组合。那就固定下来嘛,一个 byte 数对应一个英文字母不就行了?英文字母才多少个呀,这还不简单,假设 00000001 表示 A,那么 00000002 表示 B,再把小写字母一覆盖,也就占用 52 个位置,还有多的剩余呢,简直太 easy。那这种二进制数对应一个字符的方式就叫做字符编码。

字符集

美国人就按照上面的思路(思路类似,但是实际上有很多细节),搞了一个知名的编码字符集:ASCII 字符集,相当于出了一套标准,哪些二进制数和哪些英文字符一一对应,那么计算机里就怎么显示,算是解决了一个大问题。

ASCII.jpeg

ASCII 一共收录 128 个字符,包括大小写英文字母,常用英文标点符号,数学运算符 +、- 等。

那么从表中可以看到,0 位到 32 位都是特殊控制字符,比如换行、制表符什么的;33 位到 47 位是常用标点及特殊符号,例如美元符号;48 位到 57 位是阿拉伯数字 0 到 9;65 位开始才是英文字母。

你可能注意到,ASCII 值都是数字编号,并不是所谓二进制数,那其实在这些字符和二进制数的映射中间,还是依靠这些编号来充当 ”中介“ 的角色。计算机存储字符集后,字符编码为对应 ASCII 编号,编号转换为对应的二进制数,调用的时候反向解析一遍流程调用对应字符。

完美与混乱

ASCII 的出现似乎把这个大难题解决了,而且很 “完美”。但是上世纪 90 年代,中国等一大批国家加入了信息化的建设,互联网已经开始连起来了。但是,256 个编码位已经使用了一半,中文、日文等各种语言怎么在计算机里显示?要知道,汉字总数都是几万个,128 个怎么够用?而且在此之前,西欧国家搞了一堆 ASCII 的扩展,把剩余的 128 位编码位都用完了,而且彼此之间还都不兼容。完了,这是一个大问题,怎么办?

各个国家为了加快自身的建设步伐开始搞自己的字符集,反正我先用着爽,才不管你。我国就在 1980 年颁布了汉字的编码字符集,叫作:GB 2312-80。这只是一个基本字符集,只编码了 6763 个基本的常用汉字。平常使用没问题,但是毕竟我国历史源远流长、博大精深,很多人的名字都包含了生僻字,这些字在电脑里显示不出来,很多时候只能用谐音字代替。现在看到的不少成语误用大概率就是那个时期留下的弊病,还形成互联网记忆,让人们怀疑自己都学错了东西,甚至学错的人还固执的不认错。

windows 在世界风靡后,被中文汉字、日本汉字、韩国汉字搞得心态都崩了,明明都是汉字,都是一个字,你还长得不一样。微软被逼急了,直接搞了一个字符集,自己往 GB 2312 里加入一些繁体字,后来成为 GB 2312 的扩展,称为 GBK,成为汉字编码字符集的一个普通技术标准(非国家标准)。

Unicode 万国码

随着全球化的发展,特别是 WTO 等全球贸易组织的推动下,世界各国经济、文化交流日益频繁。但是各个国家还是在使用自己的字符集,这在使用电脑、打印机等各种信息交换工具时特别麻烦,亟需一种统一的字符集来统一各个国家的各种字符。

1988 年,有几个程序员正在开发一款国际化的软件,但是我们前面讲到各个国家的字符集是互不兼容的,这几个程序员是忍无可忍,恨不得地球爆炸,于是决定自己搞一套世界通用的编码字符集,于是 Unicode 项目就这样诞生了。国际化标准组织也在 1989 年开启了 UCS (Universal Multiple-Octet Coded Character Set) 标准制定,目的也是为了统一字符集。后来两拨人一看,你搞一套我搞一套,那跟没搞不是一样,所以两伙人就把双方的字符集做了合并兼容,Unicode 也才真正地得以迅速发展。两伙人从 1990 年开发到 1994 年,才正式发布了 Unicode 的第一个正式版本。

前面讲到的字符集它们基本上只有一种编码方式,但是 Unicode 却有三种:UTF-8,UTF-16,UTF-32。看到这些编码方式是不是既熟悉又陌生?很多人多多少少都见过这几种编码方式,现代标准 HTML 文档在 meta 标签里就需要声明字符集 charset=UTF-8

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
</body>
</html>

数字 8、16、32 指的其实是 bit 位,8 就是 8bit 也就是一个 byte,16、32 以此类推。之所出现这种区分是因为有些文字 —— 例如汉字是比较复杂且数量庞大的,光靠 8bit 的码位容量是不够的,需要增加对单个字符定义的 bit 长度来进行码位扩容。关于这三种编码方式的区别和细节就不再深究,毕竟也记不住,只需要了解 UTF-8 是比较常用的即可。

假设你现在用的还是旧版 windows,期末考了,你用记事本给你的好基友抄了一份答案。那么在保存文本时默认是 GBK 编码方式,可是你室友用的却是其他操作系统或者新的 windows,他的文档默认使用 UTF-8 的方式打开,结果出现一堆 “???”。你的好基友心想你个 “智慧的好兄弟”,问候过后发现你的电脑显示的文档确实正常的,你没有坑他,他还想可能是自己电脑有问题。他虽然心里纳闷,但是他女朋友催着也让他发答案,这时带着满屏 “?” 的文本被 UTF-8 编码,就会变成一堆 “锟斤拷” 之类的天书文本。然后你痛失兄弟,他痛失女友......

在智能机不普及的前些年,电脑端保存的小说在手机端打开也经常出现类似问题,这其实就是字符集编码不同导致的。

总结

我们在很多需求里会使用到英文大小写字母,记得以前小白时期,傻傻地一个一个字母的写进数组里。其实,JS 中的 String.fromCharCode 方法,可以基于 Unicode 快速生成字符。因为 Unicode 兼容 ASCII,其实可以拿 ASCII 码表来做下对照:

const codeArr = []
for (let i = 65; i < 91; i++) {
  codeArr[i] = String.fromCharCode(i)
}
console.log(codeArr) // A,B,C ... X,Y,Z

通过这个方法可以快速生成大小写英文字母或者你想要的字符。

往期推荐

你好,我是北岛贰,一名普普通通的前端。如果你觉得我的文章不错,欢迎点赞关注。推荐我这篇学习正则的文章,能够让你快速掌握 JS 正则表达式,从此正则不求人!

两小时学会 JS 正则表达式,终身不忘