unicode 转换 UTF-8,UTF-16,UTF-32编码规则(包含代码)
utf8,utf16,utf32 编码规则
工具推荐:进制转换 unicode编码查看器 ascii编码查看器 UTF编码转换
什么是 utf8
参考链接:维基百科 阮一峰
UTF-8(8-bit Unicode Transformation Format)是一种针对Unicode的可变长度字符编码,也是一种前缀码。它可以用一至四个字节对Unicode字符集中的所有有效编码点进行编码,属于Unicode标准的一部分,由于较小值的编码点一般使用频率较高,直接使用Unicode编码效率低下,大量浪费内存空间。UTF-8就是为了解决向后兼容ASCII码而设计。
- 优点:兼容 ASCII。节省空间,可占用1-4个字节。
- 缺点:UTF-8 的 ASCII 字符只占用一个字节,比较节省空间,但是更多字符的 UTF-8 编码占用的空间就要多出1/2,特别是中文、日文和韩文(CJK)这样的方块文字,它们大多需要三个字节。
编码规则
/*** utf 8 转换规则* UniCode 16进制 UTF800000000 - 0000007F 0xxxxxxx00000080 - 000007FF 110xxxxx 10xxxxxx00000800 - 0000FFFF 1110xxxx 10xxxxxx 10xxxxxx00010000 - 001FFFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx1. 举例 “严” unicode 20005 16进制 4E25 二进制 1001110001001012. 查找组 16 进制转换 2 进制00000000 - 0000007F = 0 - 111111100000080 - 000007FF = 10000000 - 1111111111100000800 - 0000FFFF = 100000000000-111111111111111100010000 - 001FFFFF = 10000000000000000-1111111111111111111113. 根据2进制比较发现 “严” 在第三组 utf8 表达式为 1110xxxx 10xxxxxx 10xxxxxx4. “严” 2进制,依次从后填入,不足补0:1110xxxx 10xxxxxx 10xxxxxx 1001110001001015. “严” utf8 2进制为 11100100 10111000 10100101 16进制为 e4 b8 a5*/const radixNum = (num, m, n) => {num = typeof num === "string" ? num : String(num);const _DEFAULT_ = {initNum: 10,};// 处理 m,n为0时转成10m = m === 0 ? _DEFAULT_.initNum : m;n = n === 0 ? _DEFAULT_.initNum : n;// 处理第三个参数n不传时, 转成10n = m && !n ? _DEFAULT_.initNum : n;// 判断radix区间let result = parseInt(num, m).toString(n);if (typeof result !== "string" && isNaN(result)) {return null;}return result;};// import { radixNum } from "../../utils/index"const UTF8_RULE = [{ start: "0", end: "1111111", rule: ["0xxxxxxx"] },{ start: "10000000", end: "11111111111", rule: ["110xxxxx", "10xxxxxx"] },{ start: "100000000000", end: "1111111111111111", rule: ["1110xxxx", "10xxxxxx", "10xxxxxx"] },{ start: "10000000000000000", end: "111111111111111111111", rule: ["11110xxx", "10xxxxxx", "10xxxxxx", "10xxxxxx"] },]const groupFormat = (codeBinary, rule) => {const codeBinaryArr = codeBinary.split("")const result = [];for (let i = rule.length - 1; i >= 0; i--) {const xAll = rule[i].match(/x/g);const pre = rule[i].slice(0, rule[i].length - xAll.length)const ruleData = codeBinaryArr.splice(-xAll.length).join("").padStart(8 - pre.length, "0")const utf8Code = pre + ruleDataresult.unshift(utf8Code)}return result}const getUtf8 = () => {// 进制const char = "严"; // 𠮷const charCodePoint = char.codePointAt(0);const charCodeBinary = radixNum(charCodePoint, 10, 2)// 分组const groupIndex = UTF8_RULE.findIndex(v => charCodeBinary >= (v.start * 1) && charCodeBinary <= (v.end * 1));const group = UTF8_RULE[groupIndex];const utf8Binary = groupFormat(charCodeBinary, group.rule)return {binary: utf8Binary,hex: utf8Binary.map(v => radixNum(v, 2, 16).toUpperCase()),decBytes: utf8Binary.map(v => radixNum(v, 2, 10)),dec: radixNum(utf8Binary.join(""), 2, 10),}}console.log(getUtf8())
字节顺序标记(BOM)
参考链接:参考链接
是位于码点U+FEFF的统一码字符的名称。当以UTF-16或UTF-32来将UCS/统一码字符所组成的字符串编码时,这个字符被用来标示其字节序。它常被用来当做标示文件是以UTF-8、UTF-16或UTF-32编码的标记
1. 字节顺序标记通常有几种涵义:. 在16位和32位的情况下,文字流的字节顺序。. 表示文字流非常有可能是Unicode编码。. 使用的是哪一种Unicode字符编码。2. 在UTF-16,UTF-32中,字节顺序标记被放置为文件或文字符串流的第一个字符,以标示在此文件或文字符串流中。防止字节读取错误,形成错误的字节。3. utf8 不需要加BOM,因为UTF-8 都具有相同的字节顺序,因此不需要字节顺序标记* BE,其后缀是 BE 即 big-endian,代表大端 ,就是将代码单元的编码从低位,也就是后一个字节开始赋值。例如:utf16-BE A 16进制为 FE FF 00 41* LE,其后缀是 LE 即 little-endian,代表小端,就是将代码单元的编码从高位,也就是前一个字节开始赋值。例如:utf16-LE A 16进制为 FF FE 41 00* 没有指定后缀,即不知道其是大小端,所以字节流开始的两个字节会表示大小端。即0XFE 0XFF表示大端,0XFF 0XFE表示小端。例如:A utf16 16进制为 FF FE 41 00
什么是 utf16
参考链接:参考链接
UTF-16是Unicode字符编码五层次模型的第三层:字符编码表(Character Encoding Form,也称为"storage format")的一种实现方式。即把Unicode字符集的抽象码位映射为16位长的整数(即码元)的序列,用于数据存储或传递。Unicode字符的码位,需要1个或者2个16位长的码元来表示,因此这是一个变长表示
- 优点:中日韩采用2个字节。
- 缺点:ASCII编码,也需要用到两个字符。
编码规则
/*** utf16 编码规则* 1. 从U+0000至U+D7FF以及从U+E000至U+FFFF的码位* 10进制为:0-55295 57344-65535* 例如:“严” unicode 20005 16进制 4E25,可见在0-55295 57344-65535区间,utf16编码为4E 25* 2. 从U + 10000到U + 10FFFF的码位* 十进制为:65536 - 1114111* 例如:“𐐷”的unicode 66615 16进制 10437 * 编码过程:* 1. 10437-10000=437 2进制为 10000110111* 2. 分割前10位,后10位,不足补0。前 00 0000 0001 后 00 0011 0111* 3. 添加 0xD800 到上值,以形成高位:0xD800 + 0x0001 = 0xD801* 4. 添加 0xDC00 到下值,以形成低位:0xDC00 + 0x0037 = 0xDC37* 5. “𐐷” UTF-16:D8 01 DC 37* 6. “𐐷” UTF-16BE:FE FF D8 01 DC 37* 7. “𐐷” UTF-16LE:FF FE 01 D8 37 DC*/const radixNum = (num, m, n) => {num = typeof num === "string" ? num : String(num);const _DEFAULT_ = {initNum: 10,};// 处理 m,n为0时转成10m = m === 0 ? _DEFAULT_.initNum : m;n = n === 0 ? _DEFAULT_.initNum : n;// 处理第三个参数n不传时, 转成10n = m && !n ? _DEFAULT_.initNum : n;// 判断radix区间let result = parseInt(num, m).toString(n);if (typeof result !== "string" && isNaN(result)) {return null;}return result;
};/*** 字符串分割数组* @param {} str 字符串* @param number num 分割位 * @returns */
const stringSplit = (str, num = 2) => {const value = str.split("");const result = [];for (let i = 0; i < value.length; i++) {const _idx = iresult.push(value.slice(i, _idx + num))i += num - 1}return result
}
// import { radixNum } from "../../utils/index"const getUtf16 = (name = "𠮷") => {// 进制const char = nameconst result = [];let index = 0;while (index < char.length) {const charCode = char.charCodeAt(index);if (charCode >= 0xD800 && charCode <= 0xDBFF) {console.log("占用4个字节!")}const radix = radixNum(charCode, 10, 16);result.push(stringSplit(radix).map(v => v.join("").toUpperCase()))index++}const BE = result.reduce((pre, cur) => { pre = pre.concat(cur); return pre }, []);const LE = result.reduce((pre, cur) => { pre = pre.concat(cur); return pre }, []).reverse();return {BE: {binary: BE.map(v => radixNum(v, 16, 2).padStart(8, 0)),hex: BE,decBytes: BE.map(v => radixNum(v, 16, 10)),dec: radixNum(BE.join(""), 16, 10),},LE: {binary: LE.map(v => radixNum(v, 16, 2).padStart(8, 0)),hex: LE,decBytes: LE.map(v => radixNum(v, 16, 10)),dec: radixNum(LE.join(""), 16, 10),}}
}console.log(getUtf16())
什么是 utf32
参考链接:参考链接
UTF-32是32位Unicode转换格式(Unicode Transformation Formats, 或UTF)的缩写。UTF-32是一种用于编码Unicode的协定,该协定使用32位比特对每个Unicode码位进行编码(但前导比特数必须为零,故仅能表示231个Unicode码位)。与其他可变长度的Unicode转换格式(UTF)相比,UTF-32编码长度是固定的,UTF-32中的每个32位值代表一个Unicode码位,并且与该码位的数值完全一致。
- 优点:UTF-32的主要优点是可以直接由Unicode码位来索引。在编码序列中查找第N个编码是一个常数时间操作。
- 缺点:UTF-32的主要缺点是每个码位使用四个字节,空间浪费较多。
编码规则:
/*** utf32 编码规则* UTF-32 让每个字符都以 32 比特,即 4 字节的长度来存储,位数不够就在前面补 0,32 比特足够表示 Unicode 中的所有字符。* 例如:* 1. “严” unicode 20005 16进制 4e25 2进制 100111000100101* 2. 已知utf32 采用4字节32比特,不足前面补0。* 3. 得到2进制为 00000000 00000000 01001110 00100101* 4. 得到16进制为 00 00 4E 25*/const radixNum = (num, m, n) => {num = typeof num === "string" ? num : String(num);const _DEFAULT_ = {initNum: 10,};// 处理 m,n为0时转成10m = m === 0 ? _DEFAULT_.initNum : m;n = n === 0 ? _DEFAULT_.initNum : n;// 处理第三个参数n不传时, 转成10n = m && !n ? _DEFAULT_.initNum : n;// 判断radix区间let result = parseInt(num, m).toString(n);if (typeof result !== "string" && isNaN(result)) {return null;}return result;
};// import { radixNum } from "../../utils/index"/*** 字符串分割数组* @param {} str 字符串* @param number num 分割位 * @returns */
const stringSplit = (str, num = 2) => {const value = str.padStart(8, "0").split("");const result = [];for (let i = 0; i < value.length; i++) {const _idx = iresult.push(value.slice(i, _idx + num))i += num - 1}return result
}const getUtf32 = (name = "严") => {// 进制const char = nameconst charCode = char.codePointAt(0);const radix = radixNum(charCode, 10, 16)const result = stringSplit(radix);const BE = result.reduce((pre, cur) => { pre = pre.concat(cur.join("").toUpperCase()); return pre }, []);const LE = result.reduce((pre, cur) => { pre = pre.concat(cur.join("").toUpperCase()); return pre }, []).reverse();return {BE: {binary: BE.map(v => radixNum(v, 16, 2).padStart(8, 0)),hex: BE,decBytes: BE.map(v => radixNum(v, 16, 10)),dec: radixNum(BE.join(""), 16, 10),},LE: {binary: LE.map(v => radixNum(v, 16, 2).padStart(8, 0)),hex: LE,decBytes: LE.map(v => radixNum(v, 16, 10)),dec: radixNum(LE.join(""), 16, 10),}}
}console.log(getUtf32())
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
