js实现unicode码字符串与utf8字节数据互转详解


Posted in Javascript onMarch 21, 2019

js的string变量存储字符串使用的是unicode编码,要保存时必须选择其他编码后进行传输,比如转成utf-8,utf-32等。存储到数据库中为utf-8编码,读取出来如何转换成正确的字符串就成了问题。现在给出解决方案,可以正确支持中文、emoji表情、英文混合的字符串编码互转。

/**
 * Created by hdwang on 2019/1/28.
 */
var convertUtf8 = (function() {

  /**
   * unicode string to utf-8
   * @param text 字符串
   * @returns {*} utf-8编码
   */
  function toBytes(text) {
    var result = [], i = 0;
    text = encodeURI(text);
    while (i < text.length) {
      var c = text.charCodeAt(i++);

      // if it is a % sign, encode the following 2 bytes as a hex value
      if (c === 37) {
        result.push(parseInt(text.substr(i, 2), 16))
        i += 2;

        // otherwise, just the actual byte
      } else {
        result.push(c)
      }
    }

    return coerceArray(result);
  }


  /**
   * utf8 byte to unicode string
   * @param utf8Bytes
   * @returns {string}
   */
  function utf8ByteToUnicodeStr(utf8Bytes){
    var unicodeStr ="";
    for (var pos = 0; pos < utf8Bytes.length;){
      var flag= utf8Bytes[pos];
      var unicode = 0 ;
      if ((flag >>>7) === 0 ) {
        unicodeStr+= String.fromCharCode(utf8Bytes[pos]);
        pos += 1;

      } else if ((flag &0xFC) === 0xFC ){
        unicode = (utf8Bytes[pos] & 0x3) << 30;
        unicode |= (utf8Bytes[pos+1] & 0x3F) << 24;
        unicode |= (utf8Bytes[pos+2] & 0x3F) << 18;
        unicode |= (utf8Bytes[pos+3] & 0x3F) << 12;
        unicode |= (utf8Bytes[pos+4] & 0x3F) << 6;
        unicode |= (utf8Bytes[pos+5] & 0x3F);
        unicodeStr+= String.fromCodePoint(unicode) ;
        pos += 6;

      }else if ((flag &0xF8) === 0xF8 ){
        unicode = (utf8Bytes[pos] & 0x7) << 24;
        unicode |= (utf8Bytes[pos+1] & 0x3F) << 18;
        unicode |= (utf8Bytes[pos+2] & 0x3F) << 12;
        unicode |= (utf8Bytes[pos+3] & 0x3F) << 6;
        unicode |= (utf8Bytes[pos+4] & 0x3F);
        unicodeStr+= String.fromCodePoint(unicode) ;
        pos += 5;

      } else if ((flag &0xF0) === 0xF0 ){
        unicode = (utf8Bytes[pos] & 0xF) << 18;
        unicode |= (utf8Bytes[pos+1] & 0x3F) << 12;
        unicode |= (utf8Bytes[pos+2] & 0x3F) << 6;
        unicode |= (utf8Bytes[pos+3] & 0x3F);
        unicodeStr+= String.fromCodePoint(unicode) ;
        pos += 4;

      } else if ((flag &0xE0) === 0xE0 ){
        unicode = (utf8Bytes[pos] & 0x1F) << 12;;
        unicode |= (utf8Bytes[pos+1] & 0x3F) << 6;
        unicode |= (utf8Bytes[pos+2] & 0x3F);
        unicodeStr+= String.fromCharCode(unicode) ;
        pos += 3;

      } else if ((flag &0xC0) === 0xC0 ){ //110
        unicode = (utf8Bytes[pos] & 0x3F) << 6;
        unicode |= (utf8Bytes[pos+1] & 0x3F);
        unicodeStr+= String.fromCharCode(unicode) ;
        pos += 2;

      } else{
        unicodeStr+= String.fromCharCode(utf8Bytes[pos]);
        pos += 1;
      }
    }
    return unicodeStr;
  }



  function checkInt(value) {
    return (parseInt(value) === value);
  }

  function checkInts(arrayish) {
    if (!checkInt(arrayish.length)) { return false; }

    for (var i = 0; i < arrayish.length; i++) {
      if (!checkInt(arrayish[i]) || arrayish[i] < 0 || arrayish[i] > 255) {
        return false;
      }
    }

    return true;
  }

  function coerceArray(arg, copy) {

    // ArrayBuffer view
    if (arg.buffer && arg.name === 'Uint8Array') {

      if (copy) {
        if (arg.slice) {
          arg = arg.slice();
        } else {
          arg = Array.prototype.slice.call(arg);
        }
      }

      return arg;
    }

    // It's an array; check it is a valid representation of a byte
    if (Array.isArray(arg)) {
      if (!checkInts(arg)) {
        throw new Error('Array contains invalid value: ' + arg);
      }

      return new Uint8Array(arg);
    }

    // Something else, but behaves like an array (maybe a Buffer? Arguments?)
    if (checkInt(arg.length) && checkInts(arg)) {
      return new Uint8Array(arg);
    }

    throw new Error('unsupported array-like object');
  }

  return {
    toBytes: toBytes,
    fromBytes: utf8ByteToUnicodeStr
  }
})()

针对emoji的字节字符,占两个unicode字符。使用String.fromCharCode也可以实现,需要进行两次fromCharCode,没有fromPointCode方便。下面展示了utf-8的4字节转换为unicode(utf-16)的过程。

//高char10位[一个unicode字符] (2+6+2=10)
unicode =  ((utf8Bytes[pos] & 0x3)) << 8 |((utf8Bytes[pos+1] & 0x3f) << 2) |((utf8Bytes[pos+2] >> 4) & 0x03);

//减去‭1F600‬中的1,这里减去6个0即可,低位char已经占据10位
unicode = unicode - parseInt('1000000',2)

//加上utf-16高char的标识符
unicode = 0xD800 + unicode;
console.log(unicode);
unicodeStr += String.fromCharCode(unicode);

//低char10位[一个unicode字符](4+6)
unicode = ((utf8Bytes[pos+2] & 0x0F) << 6) | (utf8Bytes[pos+3] & 0x3F);
//加上utf-16低char的标识符
unicode = 0xDC00 + unicode;
console.log(unicode);
unicodeStr+= String.fromCharCode(unicode);
pos += 4;

以上所述是小编给大家介绍的js实现unicode码字符串与utf8字节数据互转详解整合,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
javascript的事件描述
Sep 08 Javascript
javascript之大字符串的连接的StringBuffer 类
May 08 Javascript
Javascript 获取字符串字节数的多种方法
Jun 02 Javascript
30个让人兴奋的视差滚动(Parallax Scrolling)效果网站
Mar 04 Javascript
jquery弹出框的用法示例(2)
Aug 26 Javascript
jquery实现显示已选用户
Jul 21 Javascript
Javascript中数组方法汇总(推荐)
Apr 01 Javascript
js实现图片无缝滚动
Dec 23 Javascript
利用Javascript实现BMI计算器
Aug 16 Javascript
Html5+jQuery+CSS制作相册小记录
Dec 30 Javascript
layui固定下拉框的显示条数(有滚动条)的方法
Sep 10 Javascript
解决Vue中使用keepAlive不缓存问题
Aug 04 Javascript
详解JS取出两个数组中的不同或相同元素
Mar 20 #Javascript
详解vue中axios的使用与封装
Mar 20 #Javascript
javascript数组去重方法总结(推荐)
Mar 20 #Javascript
浅谈JavaScript面向对象--继承
Mar 20 #Javascript
小程序显示弹窗时禁止下层的内容滚动实现方法
Mar 20 #Javascript
vue踩坑记录之数组定义和赋值问题
Mar 20 #Javascript
vue实现微信二次分享以及自定义分享的示例
Mar 20 #Javascript
You might like
php目录管理函数小结
2008/09/10 PHP
phpmyadmin MySQL 加密配置方法
2009/07/05 PHP
PHP中类型转换 ,常量,系统常量,魔术常量的详解
2017/10/26 PHP
js与css实现弹出层覆盖整个页面的方法
2014/12/13 Javascript
第五篇Bootstrap 排版
2016/06/21 Javascript
浅谈javascript控制HTML5的全屏操控,浏览器兼容的问题
2016/10/10 Javascript
BootStrap实现邮件列表的分页和模态框添加邮件的功能
2016/10/13 Javascript
基于jQuery实现选项卡效果
2017/01/04 Javascript
jQuery实现导航回弹效果
2017/02/27 Javascript
使用jQuery实现鼠标点击左右按钮滑动切换
2017/08/04 jQuery
vscode下vue项目中eslint的使用方法
2019/01/13 Javascript
[50:04]DOTA2上海特级锦标赛D组小组赛#2 Liquid VS VP第二局
2016/02/28 DOTA
[53:50]CHAOS vs Mineski 2019国际邀请赛小组赛 BO2 第一场 8.16
2019/08/18 DOTA
基于Python的接口测试框架实例
2016/11/04 Python
Python实现对字符串的加密解密方法示例
2017/04/29 Python
python3 pandas 读取MySQL数据和插入的实例
2018/04/20 Python
对PyQt5中树结构的实现方法详解
2019/06/17 Python
Python+OpenCV检测灯光亮点的实现方法
2020/11/02 Python
GUESS盖尔斯法国官网:美国时尚品牌
2016/09/23 全球购物
施华洛世奇西班牙官网:SWAROVSKI西班牙
2019/06/06 全球购物
LACOSTE波兰官网:Polo衫、服装和鞋类
2020/09/29 全球购物
服务员岗位职责
2014/01/29 职场文书
酒店总经理助理职责
2014/02/12 职场文书
班级安全教育实施方案
2014/02/23 职场文书
个人欠款担保书
2014/05/20 职场文书
土木工程求职信
2014/05/29 职场文书
关于保护环境的标语
2014/06/09 职场文书
2014个人年终工作总结范文
2014/12/15 职场文书
2015年科协工作总结
2015/05/19 职场文书
2015少先队大队辅导员工作总结
2015/07/24 职场文书
爱国主义主题班会
2015/08/14 职场文书
公司中层管理培训心得体会
2016/01/11 职场文书
小学四年级班务总结该怎么写?
2019/08/16 职场文书
为了顺利买到演唱会的票用Python制作了自动抢票的脚本
2021/10/16 Python
uniapp 微信小程序 自定义tabBar 导航
2022/04/22 Javascript
git stash(储藏)的用法总结
2022/06/25 Servers