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 判断数组是否已包含了某个元素的函数
May 30 Javascript
javascript中length属性的探索
Jul 31 Javascript
EasyUI的treegrid组件动态加载数据问题的解决办法
Dec 11 Javascript
五段实用的js高级技巧
Dec 20 Javascript
jQuery 属性选择器element[herf*='value']使用示例
Oct 20 Javascript
js统计页面的来访次数实现代码
May 09 Javascript
JavaScript实现找出字符串中第一个不重复的字符
Sep 03 Javascript
jQuery简单实现网页选项卡特效
Nov 24 Javascript
vue.js入门教程之绑定class和style样式
Sep 02 Javascript
Bootstrap模态框禁用空白处点击关闭
Oct 20 Javascript
JavaScript基础之AJAX简单的小demo
Jan 29 Javascript
vuex Module将 store 分割成模块的操作
Dec 07 Vue.js
详解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
使用PHPMailer实现邮件发送代码分享
2014/10/23 PHP
javascript 定义初始化数组函数
2009/09/07 Javascript
ExtJS Window 最小化的一种方法
2009/11/18 Javascript
深入理解JavaScript系列(10) JavaScript核心(晋级高手必读篇)
2012/01/15 Javascript
『jQuery』名称冲突使用noConflict方法解决
2013/04/22 Javascript
js无刷新操作table的行和列
2014/03/27 Javascript
jquery实现鼠标经过显示下划线的渐变下拉菜单效果代码
2015/08/24 Javascript
JS实现点击登录弹出窗口同时背景色渐变动画效果
2016/03/25 Javascript
Javascript之Number对象介绍
2016/06/07 Javascript
Bootstrap栅格系统学习笔记
2016/11/25 Javascript
TypeScript学习之强制类型的转换
2016/12/27 Javascript
webpack入门+react环境配置
2017/02/08 Javascript
layer弹窗插件操作方法详解
2017/05/19 Javascript
JavaScript中document.referrer的用法详解
2017/07/04 Javascript
基于jquery实现左右上下移动效果
2018/05/02 jQuery
JavaScript引用类型RegExp基本用法详解
2018/08/09 Javascript
详解如何快速配置webpack多入口脚手架
2018/12/28 Javascript
pm2发布node配置文件ecosystem.json详解
2019/05/15 Javascript
使用ThinkJs搭建微信中控服务的实现方法
2019/08/08 Javascript
vue.js中ref和$refs的使用及示例讲解
2019/08/14 Javascript
js实现详情页放大镜效果
2020/10/28 Javascript
vue router-link 默认a标签去除下划线的实现
2020/11/06 Javascript
Python实现的二维码生成小软件
2014/07/11 Python
详解Python中类的定义与使用
2017/04/11 Python
python接口自动化测试之接口数据依赖的实现方法
2019/04/26 Python
Python socket 套接字实现通信详解
2019/08/27 Python
解决python虚拟环境切换无效的问题
2020/04/30 Python
Python+kivy BoxLayout布局示例代码详解
2020/12/28 Python
美国领先的个性化礼品商城:Personalization Mall
2019/07/27 全球购物
工作中的自我评价如何写好
2013/10/28 职场文书
毕业班联欢会主持词
2014/03/27 职场文书
学生会竞选演讲稿纪检部
2014/08/25 职场文书
2014年最新离婚协议书范本
2014/10/11 职场文书
云台山导游词
2015/02/03 职场文书
信贷客户经理岗位职责
2015/04/09 职场文书
SpringCloud超详细讲解Feign声明式服务调用
2022/06/21 Java/Android