《前端编码系列》
一、前缀符号
0b 0o 0x
| 二进制 Binary | 八进制 Octal | 十进制 Decimal | 十六进制 Hexadecimal | |
|---|---|---|---|---|
| 特定前缀 | 0b或0B | 0或·0o | 无 | 0x或0X |
| 示例1 | 0b1010 | 0o12 | 10 | 0xA |
| 示例2 | 0b11010 | 0o32 | 26 | 0x1A |
\x
在字符串中,\x前缀用来表示一个十六进制的转义序列。它后面跟着两个十六进制数字。示例:\x41 表示字符 'A'(因为A的ASCII码的十六进制是41)
\u
在字符串中,\u前缀用来表示一个Unicode字符。它后面跟着四个十六进制数字,表示该字符的Unicode码点。示例:\u0041 表示字符 'A'(因为'A'的Unicode码点是U+0041)
二、ASCII
全称"American Standard Code for Information Interchange,美国信息交换标准代码",是基于拉丁字母的一套电脑编码系统。至今为止共定义了128个字符,包括95个可显示的字符(编号范围是32-126)和33个无法显示的字符(多数为控制字符)。
ASCII 用一个字节(8个二进制位) 来储存字符,理论上一共可以表示256个字符,但最前面一位的0没有使用(统一为0),于是一共包含128个字符。
三、Unicode-统一码
3.1 码点,编码值
Unicode是一个容纳了世界上大多数文字系统的字符集,其中每个字符都有唯一的编码值(code point,常被译为 “码点” ),编码值范围是:0 - 10FFFF,一共1114112个值(超过1百万)。目标是消除不同国家地区之间由于字符集不同导致的乱码问题。
Unicode 为每个字符分配了一个唯一的码点,这个码点是一个数值,用于唯一标识字符。这些码点通常用十六进制数表示,并且前面加上 "U+" 前缀来明确指出这是一个 Unicode 码点。
Unicode仅规定了符号的二进制代码(编码值) ,但没有规定这个二进制代码如何储存 (编码方式) 。
Unicode和ASCII的关系:Unicode是在ASCII基础上发展的,对ASCII是兼容的,对于ASCII中的128个字符,它们在ASCII和Unicode中的编码值(code point)是一致的。
3.2 BOM,字节顺序
Byte Order Mark,字节顺序标记,是一个用于标识文件中字节顺序的特殊字符。在 UTF-16 和 UTF-32 这两种编码方式中可能使用 BOM
LE
Little-Endian小端序。最低有效字节储存在最低内存地址处。常作为网络协议中的字节序。举个例子:对于16位值 0xABCD
BE
Big-Endian大端序。最高有效字节储存在最低内存地址处。常作为现代计算机系统的字节序。还是以16位值0xABCD为例
3.3 UTF,编码方式
UTF(Unicode Transformation Format,Unicode 转换格式) ,主要有3种
| 特点 | 优点 | 缺点 | |
|---|---|---|---|
| UTF-32 | 使用4个字节的定长编码 | 编解码规则最简单、效率高 | Unicode编码值最大需要占用3个字节空间, 也就是说任何一个code point都会浪费1~3个字节的空间 |
| UTF-16 | 使用2或4个字节的变长编码 | - | - |
| UTF-8 | 使用1~4个字节的变长编码 | 最省空间 | - |
Q:同一个字符/码点,用UTF-32/16/8编码之后,表现出来的数值一样吗?A:不一样。
| "中" | UTF-8 | UTF-16BE | UTF-32BE |
|---|---|---|---|
| 二进制 | 11100100 10111000 10101101 | 01001110 00101101 | 00000000 00000000 01001110 00101101 |
| 十进制 | 14989485 | 20013 | 20013 |
| 十六进制 | \xE4\xB8\xAD | \u4E2D | 0000 4e2d |
| "a" | UTF-8 | UTF-16BE | UTF-32BE |
|---|---|---|---|
| 二进制 | 01100001 | 00000000 01100001 | 00000000 00000000 00000000 01100001 |
| 十进制 | 97 | 97 | 97 |
| 十六进制 | 61 | 0061 | 0000 0061 |
UTF-32
UTF-32的编码规则
- 固定为4个字节的长度
- 直接映射,Unicode码点直接映射到对应的32位值,示例:
U+0041(字母“A”) =>0x00000041 - 字节序:可以使用BOM来表示字节序(也可以不使用),LE 对应的 BOM 是
0x0000FEFF,BE 对应的 BOM 是0xFFFE0000
UTF-16
UTF-16的编码规则
- 规则1:基本平面的 code point(范围在
U+0000 ~ U+FFFF)使用2个字节表示,辅助平面的 code point(范围在U+100000 ~ U+10FFFF)使用4个字节表示 - 规则2:16个辅助平面(范围在
U+10000 ~ U+10FFFF)一共有 fffff16 也即 220 个字符,将这20位拆成2半,将高10位映射在U+D800 ~ U+DBFF,称为“高位代理”;将低10位映射在U+DC00 ~ U+DFFF,称为“低位代理”。其中U+D800 ~ U+DBFF的区间是基本平面中未使用、特定留给辅助平面区间使用的。目的是为了达到“前缀无歧义”的效果。
UTF-8
UTF-8的编码规则
- 规则1:不同范围的 code point 使用不同长度的编码
- 规则2:编码字节长度为1时前缀为
0,编码字节长度为2时前缀为110,编码字节长度为3时前缀为1110,编码字节长度为4时前缀为11110 - 规则3:除了首字节,其余字节前缀为
10
3.4 拓展1:如何查看码点
const str = "hi你好";
str.codePointAt(0); //104
str.charCodeAt(0); //104
str.codePointAt(2); //20320
str.charCodeAt(2); //20320
3.5 拓展2:如何查看原始字节流
在 Mac 上可以通过以下命令
xxd filename #查看文本文件的原始字节流,以16进制的形式
xxd -b filename #查看文本文件的原始字节流,以2进制的形式
file -I filename #查看文本文件的编码格式。输出示例:index.txt: text/plain; charset=utf-8
iconv -f UTF-8 -t UTF-16BE index.txt > index_utf16be.txt #转换文本文件的编码格式,输出为新文件
四、Uint8Array
Uint8Array 数组类型表示一个 8 位无符号整型数组,创建时内容被初始化为 0。创建完后,可以以对象的方式或使用数组下标索引的方式引用数组中的元素。
TextEncoder 接受码位流作为输入,并提供 UTF-8 字节流作为输出。
const TE = new TextEncoder();
TE.encode('h') // Uint8Array(1) [ 104 ]
参考文献
字符编码笔记:ASCII,Unicode 和 UTF-8 | 阮一峰