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 相关文章推荐
Array.slice()与Array.splice()的返回值类型
Oct 09 Javascript
javascript Array.sort() 跨浏览器下需要考虑的问题
Dec 07 Javascript
jquery的相对父元素和相对文档定位示例代码
Aug 02 Javascript
判断文件是否正在被使用的JS代码
Dec 21 Javascript
探讨JavaScript中的Rest参数和参数默认值
Jul 29 Javascript
基于jquery实现瀑布流布局
Jun 28 Javascript
js创建对象几种方式的优缺点对比
Sep 28 Javascript
ES6学习教程之块级作用域详解
Oct 09 Javascript
用react-redux实现react组件之间数据共享的方法
Jun 08 Javascript
js中对象与对象创建方法的各种方法
Feb 27 Javascript
微信小程序实现点击空白隐藏的方法示例
Aug 13 Javascript
nuxt 服务器渲染动态设置 title和seo关键字的操作
Nov 05 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 PDO中文乱码解决办法
2009/07/20 PHP
一些被忽视的PHP函数(简单整理)
2010/04/30 PHP
php保存二进制原始数据为图片的程序代码
2014/10/14 PHP
android上传图片到PHP的过程详解
2015/08/03 PHP
Zend Framework教程之动作的基类Zend_Controller_Action详解
2016/03/07 PHP
设置iframe的document.designMode后仅Firefox中其body.innerHTML为br
2012/02/27 Javascript
在新窗口打开超链接的方法小结
2013/04/14 Javascript
Javascript Objects详解
2014/09/04 Javascript
深入理解JavaScript系列(42):设计模式之原型模式详解
2015/03/04 Javascript
JQuery实现简单的服务器轮询效果实例
2016/03/31 Javascript
jQuery实现别踩白块儿网页版小游戏
2017/01/18 Javascript
浅谈jQuery的bind和unbind事件(绑定和解绑事件)
2017/03/02 Javascript
JS运动特效之任意值添加运动的方法分析
2018/01/24 Javascript
jQuery中each方法的使用详解
2018/03/18 jQuery
react native 仿微信聊天室实例代码
2019/09/17 Javascript
python生成随机密码或随机字符串的方法
2015/07/03 Python
python中requests库session对象的妙用详解
2017/10/30 Python
Python2.7 实现引入自己写的类方法
2018/04/29 Python
pandas.DataFrame.to_json按行转json的方法
2018/06/05 Python
详解python分布式进程
2018/10/08 Python
PYQT5设置textEdit自动滚屏的方法
2019/06/14 Python
Python使用百度api做人脸对比的方法
2019/08/28 Python
python不相等的两个字符串的 if 条件判断为True详解
2020/03/12 Python
python如何写出表白程序
2020/06/01 Python
在css3中background-clip属性与background-origin属性的用法介绍
2012/11/13 HTML / CSS
世界上最好的威士忌和烈性酒购买网站:The Whisky Exchange
2016/11/20 全球购物
大学系主任推荐信范文
2013/12/24 职场文书
安全保证书范文
2014/04/29 职场文书
社区服务活动总结
2014/05/07 职场文书
社会学专业求职信
2014/07/17 职场文书
尊师重教演讲稿
2014/09/04 职场文书
离婚协议书的范本
2015/01/27 职场文书
预备党员表决心的话
2015/09/22 职场文书
中国文明网2015年“向国旗敬礼”活动网上签名寄语
2015/09/24 职场文书
2016年六一文艺汇演开幕词
2016/03/04 职场文书
Django一小时写出账号密码管理系统
2021/04/29 Python