硬核基础编码篇(一)烫烫烫烫烫烫
在开发过程中偶尔会遇到关于编码、Unicode,Emoji 的问题,发现自己对这方面的基础知识并没有充分掌握。所以在经过一番查找学习之后,整理几篇通俗易懂的文章分享出来。
【硬核基础】系列的另外两篇文章,感兴趣的朋友可以了解一下:
Intro
大学刚开始接触编程的时候,使用的还是 C
语言,在 windows
平台下使用 VS
编译器写代码,经常会出现烫烫烫烫烫烫,这个诡异又很形象的字样。(是不是 💻 电脑过热?)
当然不是了,这个问题和编码息息相关,接下来的内容就是围绕这个问题,结合前端的一些实际场景进行讲解。
为什么是烫而不是其他文字?
原来是 VS
新建的文件默认的编码是根据系统 locale
选择的,默认 windows
中文系统下使用的编码格式可能是 GB2312
。
并且未初始化的栈空间用0xCC
填充(而未初始化的堆空间用0xCD
填充)。
有了上述这两个条件,两个字节 0xCCCC
对应到 GB2312
编码中的 烫
字。
"GB" === 国标拼音首字母,全称中华人民共和国国家标准字符集,不同的编码对应的字符不一样。例如使用 BIG-5(港台)编码就是【昍】,Shift_JIS(日本)就是【フ】。这个【Feature】不是中文特有的。👻
这个现象和前端有什么关联呢,如果你有在打开 HTML 网页时遇到乱码的情况,那你应该知道就是编码的问题。接下来写几个小 DEMO 了解一下。
编码字符集、解码字符集
我们在浏览器上做个小实验,打开 VSCode,新建 index.html
文件,键入以下内容,并使用浏览器打开文件。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
</head>
<body>
烫
</body>
</html>
可以看到 HTML 文件有一个特殊的 meta
标签设置了 charset
为 utf-8
。VSCode
新建文件默认使用的也是 utf-8
编码,所以浏览器上正常显示出烫
字。
若 HTML Response Header 中设置了 Content-Type: charset=UTF-8,浏览器会忽略 meta charset,使用 ResponseHeader 的 charset。
我们通过在右下角点击 [UTF-8]
- Save with encoding
修改文本编码和修改 charset
看看结果是怎么样。
文件编码 | charset | 显示结果 |
---|---|---|
utf-8 | utf-8 | 烫 |
gb2312 | utf-8 | �� |
utf-8 | gb2312 | 鐑� |
gb2312 | gb2312 | 烫 |
结论: 可以看到当文本本身使用的编码和浏览器解析时使用的编码方式不一致时,文本可能无法被正确解析,展示出“乱码“。 (建议实际操作一下,加深印象)
实体字符展示烫
在写 HTML 的时候,我们经常会用到实体字符,例如 >
表示 >
,
表示 [空格]
等等。如果要在使用这种形式展示中文烫
字,是用 烫
。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
</head>
<body>
烫
</body>
</html>
修改 HTML 文件,和👆上面一样分别修改文件编码,charset
。
文件编码 | charset | 显示结果 |
---|---|---|
utf-8 | utf-8 | 烫 |
gb2312 | utf-8 | 烫 |
utf-8 | gb2312 | 烫 |
gb2312 | gb2312 | 烫 |
结论:无论文本/meta chartset 使用哪种编码,HTML 转义序列都始终能展示正确。
&#x
开头表示的是 HTML 转义序列,后面接十六进制数字,70EB
对应”烫“字的 Unicode code point。
在前端页面里面怎么验证在 gb2312
编码中 0xcccc
就对应烫字呢?可以使用 TextDecoder/TextEncoder
API。
如何使用 JS 验证 0xcccc
使用 gb2312
编码就是烫字
打开 DevTools
,直接在 Console
面板执行以下代码
new TextDecoder("gb2312").decode(new Uint8Array([204, 204]))
// 烫
new TextDecoder('utf-8').decode(new Uint8Array([204, 204]))
// ��
Uint8Array
数组类型表示一个8位无符号整型数组(0-255),创建时内容被初始化为0。创建完后,可以以对象的方式或使用数组下标索引的方式引用数组中的元素。
十六进制的cc
= 十进制的204
,可以看到使用 gb2312
编码可以正确解码出烫
,而使用 utf-8
则输出乱码(和上面 HTML
例子中一样的乱码)
和 TextDecoder 相对应的,还有一个 TextEncoder API,不过 TextEncoder constructor 方法不允许传入编码方式,仅支持 utf-8
。
new TextEncoder().encode('烫')
// new Uint8Array [231, 131, 171]
new Uint8Array [231, 131, 171]
转换成十六进制表示是 e7 83 ab
,这是 utf-8
编码下的烫字。
如何查看文本 charset?
文本文件被保存到系统中时,会携带 charset
标记,打开文件时,编辑器就会自动按照这个编码去解码展示。
在 Linux 系统中可以使用 file
命令来查看文本编码使用的 charset
,例如 file -I index.html
。
$ file -I index.html
index.html: text/html; charset=utf-8
而当在浏览器上打开 HTML
文件时,只会以文本形式传输文本内容,解码方式取决于 meta
或者 Response Header Content-Type
。
如何十六进制形式查看文本内容?
可以使用 hexdump
命令以十六进制的形式查看文件内容,以一个只有 烫
字并且文本编码为 utf-8
的 html
文件为例。
$ hexdump index.html
0000000 e7 83 ab
0000003
0000000
- 0000003
表示的是偏移值。可以看到,文本内容就是 e7 83 ab
,和上面使用 TextEncoder
encode
结果一致。
结尾
到目前为止,我们学习了为什么烫字是“天选之子”以及和前端相关常见的编码问题,file/hexdump Command 的基础使用方法。你可能对 Unicode
,utf-8
具体是什么还不太了解。莫慌,放到下一篇文章展开。
由于时间仓促 && 水平有限,文章中必定存在大量不准确的描述、甚至错误的内容,如有发现还请善意指出。❤️
转载自:https://juejin.cn/post/7019654278012895240