UTF-8编码规则

yahone chow
8 min readMay 28, 2020

将一个任意层级的包含 file文件以及中文字符的json 通过 blob 方式上传到服务器

javascript 上传入口

// In XHR‘s Header
{
...
'Content-Type': 'application/octet-stream',
...
}

File

step 1: 
File => {fileName:'1.png',fileData:[BYTES DATA]}
step 2:
...123, 102, 105, 108, 101, 78, 97, 109, 101, 58, 39, 49, 46, 112, 110, 103, 39, 44, 102, 105, 108, 101, 68, 97, 116, 97, 58...

处理大于127字符的时候需要手动进行编码,以下是编码规则

Byte and bit

UTF-8 encoding rules

https://zh.wikipedia.org/wiki/UTF-8

UTF-8使用一至六个字节为每个字符编码(尽管如此,2003年11月UTF-8被RFC 3629重新规范,只能使用原来Unicode定义的区域,U+0000到U+10FFFF,也就是说最多四个字节)

[7, 11, 16, 21, 26, 31].map(num => {
console.log(num, 2 ** num)
});
// 7 128
// 11 2048
// 16 65536
// 21 2097152
// 26 67108864
// 31 2147483648
'h'.charCodeAt(0)
// 104
104 < 128
0x01101000
'hello world!'.split('').map(item=>'0x'+(item.charCodeAt(0)).toString(2).padStart(8,0));
// 0b01101000
// 0b01100101
// 0b01101100
// 0b01101100
// 0b01101111
// 0b00100000
// 0b01110111
// 0b01101111
// 0b01110010
// 0b01101100
// 0b01100100
// 0b00100001
// 以上均小于127
'中'.charCodeAt(0).toString(2)
// 100111000101101
// 2048 <= 20013 < 65536
// 使用三个 byte 表示
// 补全16位
// 0100111000101101
// 11100100 10111000 10101101
// 228 184 173
// 中 reversed
// 228 184 173
(228).toString(2).padStart(8,0)
11100100
(184).toString(2).padStart(8,0)
10111000
(173).toString(2).padStart(8,0)
10101101
// 11100100 10111000 10101101
// 00100111000101101
// 20013
// String.fromCharCode(20013)
// '中'

简单的实现

const UTF8Encode = ()=>{
// decimal
const unicode = char.charCodeAt(0)
let bytes = []
// 1 byte
// 0xxxxxx
if (unicode >= 0 && unicode <= 127) {
console.log(1)
bytes.push(unicode)
}
// 2 byte
// 110xxxxx 10xxxxxx
if (unicode >= 128 && unicode <= 2047) {
// unicode >> 6
// 去除最低六位的值
// B & 0b111111
// 保留最低五位的值
// B | 0b10000000
// 在前面补上110
bytes.push(unicode >> 6 & 0b11111 | 0b11000000)
// unicode & 0b111111
// 保留最低六位的值
// B | 0b10000000
// 在前面补上10
bytes.push(unicode & 0b111111 | 0b10000000)
}
// 3 byte
// 1110xxxx 10xxxxxx 10xxxxxx
if (unicode >= 2048 && unicode <= 65535) {
bytes.push(unicode >> 12 & 0b1111 | 0b11100000)
bytes.push(unicode >> 6 & 0b111111 | 0b10000000)
bytes.push(unicode & 0b111111 | 0b10000000)
}
// 4 byte
// 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
if (unicode >= 65536 && unicode <= 2097151) {
bytes.push(unicode >> 18 & 0b111 | 0b11110000)
bytes.push(unicode >> 12 & 0b111111 | 0b10000000)
bytes.push(unicode >> 6 & 0b111111 | 0b10000000)
bytes.push(unicode & 0b111111 | 0b10000000)
}
// 5 byte
// 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
if (unicode >= 2097152 && unicode <= 67108863) {
bytes.push(unicode >> 24 & 0b11 | 0b11111000)
bytes.push(unicode >> 18 & 0b111111 | 0b10000000)
bytes.push(unicode >> 12 & 0b111111 | 0b10000000)
bytes.push(unicode >> 6 & 0b111111 | 0b10000000)
bytes.push(unicode & 0b111111 | 0b10000000)
}
// 6 byte
// 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
if (unicode >= 67108864 && unicode <= 2147483647) {
bytes.push(unicode >> 30 & 0b1 | 0b11111100)
bytes.push(unicode >> 24 & 0b111111 | 0b10000000)
bytes.push(unicode >> 18 & 0b111111 | 0b10000000)
bytes.push(unicode >> 12 & 0b111111 | 0b10000000)
bytes.push(unicode >> 6 & 0b111111 | 0b10000000)
bytes.push(unicode & 0b111111 | 0b10000000)
}
}
// 简化得到
const UTF8Encode=>(char){
// decimal
const unicode = char.charCodeAt(0)
let bytes = []
if (unicode > 127) {
if (unicode > 2047) {
if (unicode > 65535) {
if (unicode > 2097151) {
if (unicode > 67108863) {
// 6 byte
// 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
bytes.push(unicode >> 30 & 0b1 | 0b11111100)
bytes.push(unicode >> 24 & 0b111111 | 0b10000000)
} else {
// 5 byte
// 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
bytes.push(unicode >> 24 & 0b11 | 0b11111000)
}
// 5 6 common
bytes.push(unicode >> 18 & 0b111111 | 0b10000000)
} else {
// 4 byte
// 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
bytes.push(unicode >> 18 & 0b111 | 0b11110000)
}
// 4 5 6 common
bytes.push(unicode >> 12 & 0b111111 | 0b10000000)
} else {
// 3 byte
bytes.push(unicode >> 12 & 0b1111 | 0b11100000)
}
// 3 4 5 6 common
bytes.push(unicode >> 6 & 0b111111 | 0b10000000)
} else {
// 2 byte
// 110xxxxx 10xxxxxx
bytes.push(unicode >> 6 & 0b11111 | 0b11000000)
}
// 2 3 4 5 6 common
bytes.push(unicode & 0b111111 | 0b10000000)
} else {
// 1 byte
// 0xxxxxx
bytes.push(unicode)
}
return bytes
}

Decode反向解码即可

此处未涵盖 emoji 的处理

--

--