前提说明
二进制,八进制,十进制,十六进制这些都只是对一个数值的书写方式,和一个数值在计算机内存中用多少字节进行存储没有任何关系。
一个数值在计算机中存储时,如果想保证存储经度,且保证存储内存消耗少,那将数值转换为二进制后,消掉所有的高位0,剩下的二进制的位数:小于等于1个字节,那就用1个字节存储;小于等于2个字节,那就用2个字节存储;小于等于3个字节,那就用3个字节存储;小于等于4个字节,那就用4个字节存储。。。
例如:
0x40 => 01000000 消掉高位0 => 1000000 => 位数小于1个字节 => 可以只用1个字节存储
如果我们非要使用4个字节存储 0x40
那使用4个字节存储的 0x40 在内存中的二进制是:00000000 00000000 00000000 01000000 浪费了3个字节内存
所以在内存中存储数值时,应该在保证精度的前提下,尽量消掉所有内存高位的0。
Unicode概述
- 我们通常说的Unicode是一个字符集,在这个字符集中每个字符都有对应的唯一十六进制值。
- Unicdoe字符集包含了全球所有的字符,所以它的体积较为庞大,如此便分为了17个平面。
- 17个平面中第一个平面为基本平面(BMP),剩下的16个为辅助平面(SMP)。
- 基本平面的字符对应十六进制值的区域为
0x0000~0xFFFF
,辅助平面中的字符对应十六进制值的区域为0x010000~0x10FFFF
UTF-32
UTF-32实质是一种重新编码计算的方式,是依附于Unicode字符集的。以Unicode字符集为参考基础,对其中的字符所对应的十六进制值进行重新计算获取一个新的十六进制值。如果我们对Unicode字符集中的所有字符都进行了UTF-32编码,那获得的值组合起来就可以说是一个UTF-32字符集了。
UTF-32的编码方式就是将 Unicode字符集中的字符对应的十六进制变为4个字节存储。
变为4个字节存储的方式就是,在二进制的高位一直添加0,直到满足4个字节为止。
例如:
0x0000 => 00000000 00000000 => 00000000 00000000 00000000 00000000 => 0x00000000
0x1EC0 => 00011110 11000000 => 00000000 00000000 00011110 11000000 => 0x00001EC0
0xFFFF => 11111111 11111111 => 00000000 00000000 11111111 11111111 => 0x0000FFFF
0x10FFFF => 00010000 11111111 11111111 => 00000000 00010000 11111111 11111111 => 0x0010FFFF
注:Unicdoe字符集中的十六进制值暂时不清楚是几个字节,但是UTF-32编码后,其值必定是4个字节的十六进制,如此UTF-32编码结果在内存中所占空间就过大了,所以通常我们不会去使用,且HTML5明确规定不使用UTF-32进行编码
UTF-16
UTF-16实质是一种重新编码计算的方式,是依附于Unicode字符集的。以Unicode字符集为参考基础,对其中的字符所对应的十六进制值进行重新计算获取一个新的十六进制值。如果我们对Unicode字符集中的所有字符都进行了UTF-16编码,那获得的值组合起来就可以说是一个UTF-16字符集了。
UTF-16的编码方式:
- Unicode字符集的基本平面中的十六进制,可以直接拿来使用,只要确保是使用2个字节进行存储的就行
- Unicode字符集的辅助平面中的十六进制(
0x010000~0x10FFFF
),都是由3个字节去进行存储的,UTF-16的编码方式是将3个字节的十六进制变为两个2个字节的十六进制。转换后的2个字节的十六进制中 第一个十六进制(称为高位H) 在0xD800~0xDBFF
范围中, 第二个十六进制(称为低位L) 在0xDC00~0xDFFF
范围中
UTF-16在辅助平面中转换公式(公式中的c
代表被转换的十六进制):
H = Math.floor((c-0x10000) / 0x400)+0xD800
L = (c - 0x10000) % 0x400 + 0xDC00
例如,转换0x1D306
:
H = Math.floor((0x1D306 - 0x10000) / 0x400) + 0xD800 = 0xD834
L = (0x1D306 - 0x10000) % 0x400 + 0xDC00 = 0xDF06
0x1D306
进行UTF-16编码后的结果就是\u0xD834\u0xDF06
UTF-16的编码方式,对于基本平面没什么影响,依然都是使用2个字节进行存储的十六进制值,而辅助平面在Unicode中都是使用3到4个字节进行存储十六进制值的,所以UTF-16编码需要将使用3到4个字节进行存储的十六进制值进行转换,转化为2个字节存储的十六进制值,所以上面将 3到4个字节进行存储十六进制值 转换为了 两个2个字节进行存储十六进制值
UTF-8
UTF-8实质是一种重新编码计算的方式,是依附于Unicode字符集的。以Unicode字符集为参考基础,对其中的字符所对应的十六进制值进行重新计算获取一个新的十六进制值。如果我们对Unicode字符集中的所有字符都进行了UTF-8编码,那获得的值组合起来就可以说是一个UTF-8字符集了。
UTF-8的编码方式(最终是要将Unicode中的十六进制值转换为由 1个 或者 2个 或者 3个 或者 4个 字节存储的十六进制值):
Unicode十六进制(高位0都去掉) | Unicode二进制(高位0都去掉) | UTF-8二进制(其中的 x 由前面的Unicode二进制值来决定) |
---|---|---|
0x0 ~ 0x7F | 0 ~ 1111111 | 0xxxxxxx |
0x80 ~ 0x7FF | 10000000 ~ 111 11111111 | 110xxxxx 10xxxxxx |
0x800 ~ 0xFFFF | 1000 00000000 ~ 11111111 11111111 | 1110xxxx 10xxxxxx 10xxxxxx |
0x10000 ~ 0x10FFFF | 1 00000000 00000000 ~ 10000 11111111 11111111 | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx |
先确定Unicode的十六进制值所在区域范围,找到对应范围的UTF-8二进制编码格式(就是上表的UTF-8二进制那一列),然后将Unicode的十六进制值转为二进制值,在将二进制值填写进对应的UTF-8二进制编码格式中(填写方式,从最后一个二进制位开始,依次从后向前填入格式中的x,多出的x填0)。
编码示例,字符 @
:
字符 @
的Unicode十六进制是0x40
,Unicode二进制是1000000
,对应的UTF-8二进制格式是0xxxxxxx
根据填写方式进行填写的最终结果:
二进制结果转为十六进制
0x0040
(\u0040
)
编码示例,字符 ˃
:
字符 ˃
的Unicode十六进制是0x2C3
,Unicode二进制是10 11000011
,对应的UTF-8二进制格式是110xxxxx 10xxxxxx
根据填写方式进行填写的最终结果:
二进制结果转为十六进制
0xCB83
(\uCB83
)