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中的eval函数
Nov 02 Javascript
window.ActiveXObject使用说明
Nov 08 Javascript
editable.js 基于jquery的表格的编辑插件
Oct 24 Javascript
简单的Jquery全选功能
Nov 07 Javascript
js调用后台、后台调用前台等方法总结
Apr 17 Javascript
jQuery配合coin-slider插件制作幻灯片效果的流程解析
May 13 Javascript
jQuery购物网页经典制作案例
Aug 19 Javascript
jQuery 判断元素整理汇总
Feb 28 Javascript
vue router下的html5 history在iis服务器上的设置方法
Oct 18 Javascript
优雅的使用javascript递归画一棵结构树示例代码
Sep 22 Javascript
详解简单易懂的 ES6 Iterators 指南和示例
Sep 24 Javascript
vue中echarts引入中国地图的案例
Jul 28 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中选择什么接口(mysql、mysqli)访问mysql
2013/02/06 PHP
自定义session存储机制避免会话保持问题
2014/10/08 PHP
PHP生成不重复标识符的方法
2014/11/21 PHP
php设计模式之装饰模式应用案例详解
2019/06/17 PHP
javascript操纵OGNL标签示例代码
2014/06/16 Javascript
jquery实现的判断倒计时是否结束代码
2016/02/05 Javascript
深入理解事件冒泡(Bubble)和事件捕捉(capture)
2016/05/28 Javascript
利用JS实现数字增长
2016/07/28 Javascript
JavaScript数组_动力节点Java学院整理
2017/06/26 Javascript
详解Vue.js组件可复用性的混合(mixin)方式和自定义指令
2017/09/06 Javascript
解决bootstrap模态框数据缓存的问题方法
2018/08/10 Javascript
Vue form表单动态添加组件实战案例
2019/09/02 Javascript
关于angular浏览器兼容性问题的解决方案
2020/07/26 Javascript
[36:33]完美世界DOTA2联赛循环赛 Matador vs Forest 第一场 11.06
2020/11/06 DOTA
python实现定时同步本机与北京时间的方法
2015/03/24 Python
解决python nohup linux 后台运行输出的问题
2018/05/11 Python
Python requests发送post请求的一些疑点
2018/05/20 Python
Python中return self的用法详解
2018/07/27 Python
python实现连连看辅助之图像识别延伸
2019/07/17 Python
利用Python绘制有趣的万圣节南瓜怪效果
2019/10/31 Python
tensorflow将图片保存为tfrecord和tfrecord的读取方式
2020/02/17 Python
django 取消csrf限制的实例
2020/03/13 Python
TensorFlow2.X使用图片制作简单的数据集训练模型
2020/04/08 Python
Python文件时间操作步骤代码详解
2020/04/13 Python
Flask中jinja2的继承实现方法及实例
2021/03/03 Python
印度在线内衣和时尚目的地:Zivame
2017/09/28 全球购物
美国著名的女性内衣零售商:Frederick’s of Hollywood
2018/02/24 全球购物
沃达丰英国有限公司:Vodafone英国
2019/04/16 全球购物
官方授权图形T恤和服装:Fifth Sun
2019/06/12 全球购物
德国富尔达运动鞋店:43einhalb
2020/12/25 全球购物
在weblogic中发布ejb需涉及到哪些配置文件
2012/01/17 面试题
师范教师大学生职业生涯规划范文
2014/01/05 职场文书
电子信息工程专业求职信
2014/06/28 职场文书
起诉状范本
2015/05/20 职场文书
田径运动会广播稿
2015/08/19 职场文书
pytorch实现ResNet结构的实例代码
2021/05/17 Python