В статье используется JS для простой реализации кодировки UTF-8 и кодировки Base64.Прочитайте эту статью, чтобы понять преобразование между Unicode и UTF-8 и понять, почему кодировка Base64 увеличивает объем данных.
резюме:
- Простое понимание Юникода
- Кодировка UTF-8
- Кодировка Base64
- Суммировать
Коллекция кодировок Unicode, ASCII, GB2312 и т. д., похожая на словарь. Символы похожи на слова, а кодировка символов аналогична тому, какая страница и строка слова в словаре. Когда разные системы используют один и тот же словарь для поиска одной и той же кодировки, полученные символы будут согласованными.
Как показано ниже:
1. Простое понимание Unicode
Unicode is a computing industry standard for the consistent encoding, representation, and handling of text expressed in most of the world's writing systems.
До создания Unicode разные языки имели разные наборы кодировок, ASCII, GB2312 и т. д. также были наборами кодировок в процессе разработки, и эти наборы кодировок конфликтовали друг с другом, что создавало проблемы для связи между разными языковыми системами. Потому что два одинаковых символа могут иметь совершенно разные значения в разных системах кодирования. Так появился Unicode, набор кодировок Unicode предоставляет уникальный номер для каждого символа, независимо от платформы, программы, языка, набор символов Unicode широко используется.
Программы Javascript написаны с использованием набора символов Unicode, и каждый символ в строке обычно происходит из набора символов Unicode.
Набор символов Unicode похож на словарь, а символы похожи на слова. Кодовое значение Unicode символа аналогично странице и строке слова в словаре.
2. Кодировка UTF-8
2.1 Зачем нам нужна кодировка для передачи с набором символов Unicode?
Поскольку кодировка Unicode преобразуется в двоичную, это строка из 0 и 1. При передаче другой стороне необходимо правило для разделения этой строки из 0 и 1 и последующего перекодирования.
Итак, существуют «правила сегментации передачи», кодировки UTF-n.
8bit = 1byte
UTF (Universal Transformation Format, универсальный формат передачи), по сути, не изменяет код каждого символа в наборе символов, устанавливает новый метод кодирования и сопоставляет код символа с кодировкой при передаче посредством этого метода кодирования. Задача состоит в том, чтобы сэкономить трафик и место на жестком диске при использовании набора символов Unicode для унификации.
место хранения
Unicode — это набор символов, определяющий двоичный код символа, но не определяющий, как следует хранить двоичный код (т. е. сколько байтов он занимает), поэтому существуют разные реализации хранения.
UTF-32
Символы представлены четырьмя байтами
UTF-16
Символы представлены двумя или четырьмя байтами
UTF-8
Метод кодирования переменной длины, который использует 1–4 байта для представления символов по мере необходимости (доставка по требованию экономит трафик и место на жестком диске, поэтому UTF-8 широко используется)
2.2 Правила кодирования UTF-8
- Для однобайтового символа первый бит байта устанавливается равным 0, а следующие 7 битов являются Unicode-кодом символа.
- Для n-байтовых символов (n > 1) первые n бит первого байта устанавливаются в 1, n+1-й бит устанавливается в 0, а первые два бита следующих байтов устанавливаются в 10. Остальное, все это кодировка Unicode этого символа.
например: кодировка UTF-8 символа Луо
Используйте codePointAt, чтобы получить Unicode-кодировку символа, подтвердите, что он представлен несколькими байтами, а затем заполните в соответствии с правилами.
Процесс кодирования:
Дополнительная информация:
ES6 предоставляет метод **codePointAt()**, который может правильно обрабатывать символы, хранящиеся в байтах, и возвращать кодовую точку (кодировку Unicode) символа.
ES6 предоставляет метод **String.fromCodePoint()** для правильной обработки кодовой точки (кодировка Unicode) и возврата символа, соответствующего кодовой точке (кодировка Unicode).
2.3 Простая реализация кодирования и декодирования UTF-8
// 编码
function encodeUtf8(str) {
var bytes = []
for (ch of str) {
// for...of循环,能正确识别 32 位的 UTF-16 字符, 可以查阅资料了解。
let code = ch.codePointAt(0)
if (code >= 65536 && code <= 1114111) {// 位运算, 补齐8位
bytes.push((code >> 18) | 0xf0)
bytes.push(((code >> 12) & 0x3f) | 0x80)
bytes.push(((code >> 6) & 0x3f) | 0x80)
bytes.push((code & 0x3f) | 0x80)
} else if (code >= 2048 && code <= 65535) {
bytes.push((code >> 12) | 0xe0)
bytes.push(((code >> 6) & 0x3f) | 0x80)
bytes.push((code & 0x3f) | 0x80)
} else if (code >= 128 && code <= 2047) {
bytes.push((code >> 6) | 0xc0)
bytes.push((code & 0x3f) | 0x80)
} else {
bytes.push(code)
}
}
return bytes
}
// 补位
function padStart(str, len, prefix) {
return ((new Array(len + 1).join(prefix)) + str).slice(-len) // 也可用 new Array(len+1).fill(0)
}
// 解码
function decodeUtf8(str) {
let strValue = ''
let obStr = [...str].map((ch)=> {
// 一位16进制数 转二进制 需要四位来表示 补全位数
return padStart(parseInt(ch,16).toString(2), 4, 0)
}).join('').match(/\d{8}/g).map((item)=> parseInt(item,2))
for (var i = 0; i < obStr.length; ) {
let code = obStr[i]
let code1, code2, code3, code4, hex
// 比较 前4 位 parseInt(11110000,2) = 240 4个字节
if ((code & 240) == 240) {
code1 = (code & 0x03).toString(2)
code2 = padStart((obStr[i + 1] & 0x3f).toString(2),6, '0')
code3 = padStart((obStr[i + 2] & 0x3f).toString(2),6, '0')
code4 = padStart((obStr[i + 3] & 0x3f).toString(2),6, '0')
hex = parseInt((code1 + code2 + code3 + code4),2)
strValue = strValue + String.fromCodePoint(hex)
i = i + 4
} else if ((code & 224) == 224) { // 3个字节表
code1 = (code & 0x07).toString(2)
code2 = padStart((obStr[i + 1] & 0x3f).toString(2),6, '0')
code3 = padStart((obStr[i + 2]& 0x3f).toString(2),6, '0')
hex = parseInt((code1 + code2 + code3),2)
strValue = strValue + String.fromCodePoint(hex)
i = i + 3
} else if ((code & 192) == 192) {// 2个字节表
code1 = (code & 0x0f).toString(2)
code2 = padStart((obStr[i + 1] & 0x3f).toString(2),6, '0')
hex = parseInt((obStr + code2),2)
strValue = strValue + String.fromCodePoint(hex)
i = i + 2
} else {
hex = code
strValue = strValue + String.fromCodePoint(code)
i = i + 1
}
}
return strValue
}
// byte to hex
function transferHex(bytes) {
let s = ''
bytes &&
bytes.forEach(ch => {
s = s + ch.toString(16)
})
return s
}
let text = "罗小步 啊哈哈 𠮷 ssdf 34534 ASD"
let strHax = transferHex(encodeUtf8(text))
console.log(strHax)
let str = decodeUtf8(strHax)
console.log(str)
console.log("test ok?", text === str)
3. Кодировка Base64
3.1 Правила кодирования Base64
Правила: метод кодирования Base64 требует, чтобы каждые три 8-битных байта были преобразованы в четыре 6-битных байта, а затем перед каждым 6-битным байтом добавлялись два старших нуля, чтобы сформировать четыре 8-битных байта.
Если двоичные данные, подлежащие кодированию, не кратны 3, последний оставшийся код Base64 будет дополнен нулями в конце, а затем в конце кодирования будет добавлено одно или два знака «=».
Каждые 8 бит кодируются как: CHARST[paresInt(8bit ,2)]
CHARTS = ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/
Процесс кодирования:
3.2 Простая реализация кодирования и декодирования Base64
const CHARTS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
const prefix = '='
const prefixTwo = 2
const prefixfour = 4
function padEnd(str, len, prefix) {
return (str + (new Array(len + 1)).join(prefix)).slice(0, len)
}
function padStart(str, len, prefix) {
return ((new Array(len + 1).join(prefix)) + str).slice(-len)
}
// 编码
function encodeBase64(str){
let byteStr = ''
for(let ch of encodeUtf8(str)){
byteStr = byteStr + padStart(ch.toString(2),8,0)
}
let rest = byteStr.length % 6 // 余2 就是剩下了一个字节,余 4 就是剩下两个字节
let restStr = rest === prefixTwo ? '==' :'='
let prefixzero = rest === prefixTwo ? prefixfour: prefixTwo
byteStr = padEnd(byteStr , byteStr.length + prefixzero,'0')
return byteStr.match(/(\d{6})/g).map(val=>parseInt(val,2)).map(val=>CHARTS[val]).join('') + restStr;
}
// 解码
function decodeBase64(str) {
let matchTime = str.match(/(ha)/g)
let [...restStr] = str.replace(/=/g,'')
restStr = restStr.map((item)=> {
let value = CHARTS.indexOf(item)
return padStart(value.toString(2),6,0)
}).join('').match(/(\d{8})/g).map((item)=>parseInt(item,2).toString(16)).join()
console.log(restStr)
return decodeUtf8(restStr)
}
let text = "罗小步 啊哈哈 𠮷 ssdf 34534 ASD"
let strHax = encodeBase64(text)
console.log(strHax)
let str = decodeBase64(strHax)
console.log(str)
console.log("test ok?", text === str)
Метод кодирования Base64 требует, чтобы каждые три 8-битных байта были преобразованы в четыре 6-битных байта, а кодирование увеличивает длину данных на 1/3 от исходной.
4. Резюме
Кодировка — это просто представление набора символов. В статье используется js для простой реализации кодировки utf8 и кодировки base64. Реализация кода относительно грубая, а понимание неточное, так же прошу совета. Добро пожаловать, чтобы обсудить и учиться вместе.