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 相关文章推荐
接收键盘指令的脚本
Jun 26 Javascript
ASP Json Parser修正版
Dec 06 Javascript
jQuery之选择组件的深入解析
Jun 19 Javascript
js Math 对象的方法
Sep 01 Javascript
js中的referrer返回上一页使用介绍
Sep 26 Javascript
JS保留两位小数,多位小数的示例代码
Jan 07 Javascript
jQuery实现渐变弹出层和弹出菜单的方法
Feb 20 Javascript
jQuery EasyUI Dialog拖不下来如何解决
Sep 28 Javascript
JS中动态创建元素的三种方法总结(推荐)
Oct 20 Javascript
jQuery焦点图左右转换效果
Dec 12 Javascript
简单实现js菜单栏切换效果
Mar 04 Javascript
vue vantUI tab切换时 list组件不触发load事件的问题及解决方法
Feb 14 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
apache+php完美解决301重定向的两种方法
2011/06/08 PHP
PHP实现视频文件上传完整实例
2014/08/28 PHP
PHP将字符串首字母大小写转换的实例
2017/01/21 PHP
JavaScript的面向对象方法以及差别
2008/03/31 Javascript
JavaScript 学习点滴记录
2009/04/24 Javascript
jQuery Study Notes学习笔记 (二)
2010/08/04 Javascript
40个有创意的jQuery图片和内容滑动及弹出插件收藏集之三
2012/01/03 Javascript
js登录弹出层特效
2014/03/07 Javascript
IE8中使用javascript动态加载CSS的解决方法
2014/06/17 Javascript
js简单获取表单中单选按钮值的方法
2016/08/23 Javascript
AngularJS ngModel实现指令与输入直接的数据通信
2016/09/21 Javascript
Extjs让combobox写起来简洁又漂亮
2017/01/05 Javascript
jQuery中table数据的值拷贝和拆分
2017/03/19 Javascript
用JS实现简单的登录验证功能
2017/07/28 Javascript
JavaScript实现随机点名器实例详解
2019/05/07 Javascript
React Native 混合开发多入口加载方式详解
2019/09/23 Javascript
iview实现动态表单和自定义验证时间段重叠
2021/01/10 Javascript
简单的抓取淘宝图片的Python爬虫
2014/12/25 Python
Python Property属性的2种用法
2015/06/21 Python
Pandas 同元素多列去重的实例
2018/07/03 Python
windows下pycharm安装、创建文件、配置默认模板
2018/07/31 Python
python 通过SSHTunnelForwarder隧道连接redis的方法
2019/02/19 Python
使用opencv将视频帧转成图片输出
2019/12/10 Python
pytorch 准备、训练和测试自己的图片数据的方法
2020/01/10 Python
python3.7通过thrift操作hbase的示例代码
2020/01/14 Python
python IP地址转整数
2020/11/20 Python
35款精致的 CSS3 和 HTML5 网页模板 推荐
2012/08/03 HTML / CSS
H5仿微信界面教程(一)
2017/07/05 HTML / CSS
html5使用canvas实现跟随光标跳动的火焰效果
2014/01/07 HTML / CSS
制定岗位职责的原则
2013/11/08 职场文书
宣传工作经验材料
2014/06/02 职场文书
大学生赌博检讨书
2014/09/22 职场文书
党员领导干部民主生活会批评与自我批评发言
2014/09/28 职场文书
公司放假通知范文
2015/04/14 职场文书
六五普法先进个人主要事迹材料
2015/11/03 职场文书
数据结构课程设计心得体会
2016/01/15 职场文书