前端怎么表情符号转码处理

转换的原因:
emoji用到的字符是4字节的utf-16(utf-16有2字节和4字节两种编码),而后端数据库是采用的utf-8,最多允许3字节的字符。插入数据库变成乱码的???,接口做了校验的还会报错。
utf-16
从U+0000至U+D7FF以及从U+E000至U+FFFF的码位

第一个Unicode平面(码位从U+0000至U+FFFF)包含了最常用的字符。该平面被称为基本多语言平面,缩写为BMP(Basic Multilingual Plane,BMP)。UTF-16与UCS-2编码这个范围内的码位为16位元长的单个码元,数值等价于对应的码位。BMP中的这些码位是仅有的可以在UCS-2中表示的码位。

从U+10000到U+10FFFF的码位

辅助平面(Supplementary Planes)中的码位,在UTF-16中被编码为一对16位元长的码元(即32位,4字节),称作代理对(Surrogate Pair),具体方法是:
UTF-16解码
lead \ trail DC00 DC01 … DFFF
D800 10000 10001 … 103FF
D801 10400 10401 … 107FF
⋮ ⋮ ⋮ ⋱ ⋮
DBFF 10FC00 10FC01 … 10FFFF
码位减去 0x10000,得到的值的范围为20位元长的 0…0xFFFFF。
高位的10位元的值(值的范围为 0…0x3FF)被加上 0xD800 得到第一个码元或称作高位代理(high surrogate),值的范围是 0xD800…0xDBFF。由于高位代理比低位代理的值要小,所以为了避免混淆使用,Unicode标准现在称高位代理为前导代理(lead surrogates)。
低位的10位元的值(值的范围也是 0…0x3FF)被加上 0xDC00 得到第二个码元或称作低位代理(low surrogate),现在值的范围是 0xDC00…0xDFFF。由于低位代理比高位代理的值要大,所以为了避免混淆使用,Unicode标准现在称低位代理为后尾代理(trail surrogates)。

假设要将U+64321(16进制)转成UTF-16编码。因为它超过U+FFFF,所以他必须编译成32位(4个byte)的格式,如下所示:

V = 0x64321
Vx = V - 0x10000
= 0x54321
= 0101 0100 0011 0010 0001

Vh = 01 0101 0000 // Vx的高位部份的10 bits
Vl = 11 0010 0001 // Vx的低位部份的10 bits
w1 = 0xD800 //結果的前16位元初始值
w2 = 0xDC00 //結果的後16位元初始值

w1 = w1 | Vh
= 1101 1000 0000 0000
 |       01 0101 0000
= 1101 1001 0101 0000
= 0xD950

w2 = w2 | Vl
= 1101 1100 0000 0000
 |       11 0010 0001
= 1101 1111 0010 0001
= 0xDF21

所以这个字U+64321最后正确的UTF-16编码应该是:
0xD950 0xDF21
而在小尾序中最后的编码应该是:
0x50D9 0x21DF

var emoji={
	// 表情转码
    utf16toEntities(str) {
      const patt = /[\ud800-\udbff][\udc00-\udfff]/g; // 检测utf16字符正则,检测是否超过U+FFFF
      str = str.replace(patt, (char) => {
        let H;
        let L;
        let code;
        let s;

        if (char.length === 2) {
          H = char.charCodeAt(0); // 取出高位
          L = char.charCodeAt(1); // 取出低位
          code = (H - 0xD800) * 0x400 + 0x10000 + L - 0xDC00; // 转换算法
          s = `&#${code};`;
        } else {
          s = char;
        }

        return s;
      });

      return str;
    },
    // 表情解码
    entitiestoUtf16(strObj) {
      const patt = /&#\d+;/g;
      const arr = strObj.match(patt) || [];

      let H;
      let L;
      let code;

      for (let i = 0; i < arr.length; i += 1) {
        code = arr[i];
        code = code.replace('&#', '').replace(';', '');
        // 高位   0x400=2^10=1024
        H = Math.floor((code - 0x10000) / 0x400) + 0xD800;
        // 低位
        L = ((code - 0x10000) % 0x400) + 0xDC00;
        code = `&#${code};`;
        const s = String.fromCharCode(H, L);
        strObj = strObj.replace(code, s);
      }
      return strObj;
    }
}
let s="👇👉👈🙌"
const strIn=emoji.utf16toEntities(s)
console.log(strIn) //&#128071;&#128073;&#128072;&#128588;
const strout=emoji.entitiestoUtf16(strIn)
console.log(strout)//"👇👉👈🙌"

fromCharCode()
可接受一个指定的 Unicode 值,然后返回一个字符串。
.fromCharCode(numX,numX,…,numX)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值