/** ***************************************** * Created by edonet@163.com * Created on 2020-02-06 11:26:57 ***************************************** * 1字节 0xxxxxxx * 2字节 110xxxxx 10xxxxxx * 3字节 1110xxxx 10xxxxxx 10xxxxxx * 4字节 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx * 5字节 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx * 6字节 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */ 'use strict'; /** ***************************************** * 抛出接口 ***************************************** */ export const utf8 = { encode, decode }; /** ***************************************** * 编码数据 ***************************************** */ export function encode(str: string): number[] { let arr: number[] = [], len = str.length, i = 0; // 处理字符 while (i < len) { let code = str.charCodeAt(i ++); // 粘合字符 if (code >= 0xD800 && code <= 0xDBFF && i < len) { let next = str.charCodeAt(i); // 校验字符 if (next >= 0xDC00 && next <= 0xDFFF) { code = (code - 0xD800) * 0x400 + next - 0xDC00 + 0x10000; i ++; } } // 生成编码 if (code < 0x80) { arr.push(code); } else { arr = [...arr, ...subareaCode(code)]; } } // 返回结果 return arr; } /** ***************************************** * 解码数据 ***************************************** */ export function decode(arr: ArrayLike, start = 0, end = arr.length): string { let data: string[] = []; // 遍历编码 while (start < end) { let code = arr[start ++]; // 兼容负数 if (code < 0) { code &= 0xFF; } // 处理多字节编码 if (code > 0x7F) { let bytes: number[] = [], k = 0x40; // 查找字符 if (code < 0xF8 && code > 0xC0) { while (code & k) { if (arr[start] >> 6 === 2 && k > 2) { k = k >> 1; bytes.push(arr[start ++] & 0x3F); } else { k = 0x40; break; } } } // 合并字节 code = k === 0x40 ? 0xFFFD : adhereCode(code & (k - 1), bytes); } // 生成字符 if (code <= 0xFFFF) { data.push(String.fromCharCode(code)); } else { code -= 0x10000; data.push(String.fromCharCode((code >> 10) + 0xD800, (code % 0x400) + 0xDC00)); } } // 返回结果 return data.join(''); } /** ***************************************** * 合并字节 ***************************************** */ function adhereCode(code: number, arr: number[] = []): number { let len = arr.length; // 合并字节 while (len --) { code = (code << 6) | arr.shift() as number; } // 返回结果 return code; } /** ***************************************** * 分离字节 ***************************************** */ function subareaCode(code: number): number[] { let arr: number[] = []; // 分离字符 for (; code > (0x3F >> arr.length); code = code >> 6) { arr.unshift(code & 0x3F | 0x80); } // 转换编码 arr.unshift((0xFF - (0x7F >> arr.length)) | code); // 返回结果 return arr; }