通过javascript进行UTF-8编码的实现方法


Posted in Javascript onJune 27, 2016

javascript的字符集:

javascript程序是使用Unicode字符集编写的。Unicode是ASCII和Latin-1的超集,并支持地球上几乎所有的语言。ECMAScript3要求JavaScript必须支持Unicode2.1及后续版本,ECMAScript5则要求支持Unicode3及后续版本。所以,我们编写出来的

javascript程序,都是使用Unicode编码的。

UTF-8

UTF-8(UTF8-bit Unicode Transformation Format)是一种针对Unicode的可变长度字符编码,也是一种前缀码。

它可以用来表示Unicode标准中的任何字符,且其编码中的第一个字节仍与ASCII兼容,这使得原来处理ASCII字符的软件无须或只须做少部分修改,即可继续使用。因此,它逐渐成为电子邮件、网页及其他存储或发送文字的应用中,优先采用的编码。

目前大部分的网站,都是使用的UTF-8编码。

将javascript生成的Unicode编码字符串转为UTF-8编码的字符串

如标题所说的应用场景十分常见,例如发送一段二进制到服务器时,服务器规定该二进制内容的编码必须为UTF-8。这种情况下,我们必须就要通过程序将javascript的Unicode字符串转为UTF-8编码的字符串。

转换方法

转换之前我们必须了解Unicode的编码结构是固定的。

不信可以试一试 String 的 charCodeAt 这个方法,看看返回的 charCode 占几个字节。

•英文占1个字符,汉字占2个字符

然而,UTF-8的编码结构长度是根据某单个字符的大小来决定长度有多少。

下面为单个字符的大小占用几个字节。单个unicode字符编码之后的最大长度为6个字节。

•1个字节:Unicode码为0 - 127
•2个字节:Unicode码为128 - 2047
•3个字节:Unicode码为2048 - 0xFFFF
•4个字节:Unicode码为65536 - 0x1FFFFF
•5个字节:Unicode码为0x200000 - 0x3FFFFFF
•6个字节:Unicode码为0x4000000 - 0x7FFFFFFF

具体请看图片:

通过javascript进行UTF-8编码的实现方法

因为英文和英文字符的Unicode码为0 - 127,所以英文在Unicode和UTF-8中的长度和字节都是一致的,只占用1个字节。这也就是为什么UTF8是Unicode的超集!

现在我们再来讨论汉字,因为汉字的unicode码区间为0x2e80 - 0x9fff, 所以汉字在UTF8中的长度最长为3个字节。

那么汉字是如何从Unicode的2个字节转换为UTF8的三个字节的哪?

假设我需要把汉字"中"转为UTF-8的编码

1、获取汉字Unicode值大小

var str = '中';
var charCode = str.charCodeAt(0);
console.log(charCode); // => 20013

2、根据大小判断UTF8的长度

由上一步我们得到汉字"中"的charCode为20013.然后我们发现20013位于2048 - 0xFFFF这个区间里,所以汉字"中"应该在UTF8中占3个字节。

3、补码

既然知道汉字"中"需要占3个字节,那么这3个字节如何得到哪?

这就需要设计到补码,具体补码逻辑如下:

通过javascript进行UTF-8编码的实现方法

好吧,我知道这个图你们也看不明白,还是我来讲吧!

具体的补位码如下,"x"表示空位,用来补位的。

•0xxxxxxx
•110xxxxx 10xxxxxx
•1110xxxx 10xxxxxx 10xxxxxx
•11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
•111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
•1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx

warning:有没有发现?补位码第一个字节前面有几个1就表示整个UTF-8编码占多少个字节!UTF-8解码为Unicode就是利用的这个特点哦~

我们先举个简单的例子。把英文字母"A"转为UTF8编码。

1、“A”的charCode为65
2、65位于0-127的区间,所以“A”占一个字节
3、UTF8中一个字节的补位为0xxxxxxx,x表示的是空位,是用来补位的。
4、将65转为二进制得到1000001
5、将1000001按照从前到后的顺序,依次补到1xxxxxxx的空位中,得到01000001
6、将11000001转为字符串,得到"A"
7、最终,"A"为UTF8编码之后“A”

通过这个小例子,我们是否再次验证了UTF-8是Unicode的超集!

好了,我们现在再回到汉字"中"上,之前我们已经得到了"中"的charCode为20013,二进制为01001110 00101101。具体如下:

var code = 20013;
code.toString(2); 
// => 100111000101101 等同于 01001110 00101101

然后,我们按照上面“A”补位的方法,来给"中"补位。
将01001110 00101101按照从前到后的顺序依此补位到1110xxxx 10xxxxxx 10xxxxxx上.得到11100100 10111000 10101101.

4、得到UTF8编码的内容

通过上面的步骤,我们得到了"中"的三个UTF8字节,11100100 10111000 10101101。

我们将每个字节转为16进制,得到0xE4 0xB8 0xAD;
那么这个0xE4 0xB8 0xAD就是我们最终得到的UTF8编码了。

我们使用nodejs的buffer来验证一下是否正确。

var buffer = new Buffer('中'); 
console.log(buffer.length); // => 3
console.log(buffer); // => <Buffer e4 b8 ad>
// 最终得到三个字节 0xe4 0xb8 0xad

因为16进制是不分大小写的,所以是不是跟我们算出来0xE4 0xB8 0xAD一模一样。

将上面的编码逻辑写到一个函数中。

// 将字符串格式化为UTF8编码的字节
var writeUTF = function (str, isGetBytes) {
   var back = [];
   var byteSize = 0;
   for (var i = 0; i < str.length; i++) {
     var code = str.charCodeAt(i);
     if (0x00 <= code && code <= 0x7f) {
        byteSize += 1;
        back.push(code);
     } else if (0x80 <= code && code <= 0x7ff) {
        byteSize += 2;
        back.push((192 | (31 & (code >> 6))));
        back.push((128 | (63 & code)))
     } else if ((0x800 <= code && code <= 0xd7ff) 
         || (0xe000 <= code && code <= 0xffff)) {
        byteSize += 3;
        back.push((224 | (15 & (code >> 12))));
        back.push((128 | (63 & (code >> 6))));
        back.push((128 | (63 & code)))
     }
    }
    for (i = 0; i < back.length; i++) {
      back[i] &= 0xff;
    }
    if (isGetBytes) {
      return back
    }
    if (byteSize <= 0xff) {
      return [0, byteSize].concat(back);
    } else {
      return [byteSize >> 8, byteSize & 0xff].concat(back);
    }
}

writeUTF('中'); // => [0, 3, 228, 184, 173] 
// 前两位表示后面utf8字节的长度。因为长度为3,所以前两个字节为`0,3`
// 内容为`228, 184, 173`转成16进制就是`0xE4 0xB8 0xAD`
// 读取UTF8编码的字节,并专为Unicode的字符串
var readUTF = function (arr) {
  if (typeof arr === 'string') {
    return arr;
  }
  var UTF = '', _arr = this.init(arr);
  for (var i = 0; i < _arr.length; i++) {
    var one = _arr[i].toString(2),
        v = one.match(/^1+?(?=0)/);
    if (v && one.length == 8) {
      var bytesLength = v[0].length;
      var store = _arr[i].toString(2).slice(7 - bytesLength);
      for (var st = 1; st < bytesLength; st++) {
        store += _arr[st + i].toString(2).slice(2)
      }
      UTF += String.fromCharCode(parseInt(store, 2));
      i += bytesLength - 1
    } else {
      UTF += String.fromCharCode(_arr[i])
    }
  }
  return UTF
}

readUTF([0, 3, 228, 184, 173]); => '中'

另外一种将中文解析得到UTF8字节码的方法

另外一种比较简单的将中文转为UTF8字节码的方法比较简单,浏览器也提供了一个方法,而且这个方法大家都一直在用,是什么哪?就是encodeURI。当然,encodeURIComponent也是可以的。

没错,就是这个方法。那么这个方法是怎么将一个Unicode编码的中文转为UTF8的字节码嘞?

var str = '中';

var code = encodeURI(str);

console.log(code); // => %E4%B8%AD

有没有发现得到了一个转义后的字符串,而且这个字符串中的内容和我之前在上面得到的字节码是一样的~~~。

下面我们将%E4%B8%AD转为一个number数组。

var codeList = code.split('%');

codeList = codeList.map(item => parseInt(item,16));

console.log(codeList); // => [228, 184, 173]

如此简单,有木有~~~

这个简便方法的原理是什么?

这里就涉及到的URI中的querystring编码的问题了。因为按照规定,URI中的querystring必须按照UTF8的编码进行传输,而JavaScript是Unicode的,所以浏览器就给我们提供了一个方法,也就是encodeURI/encodeURIComponent方法。这个方法会讲
非英文字符(这里考虑下,为什么是非英文字符?)先转为UTF8的字节码,然后前面加个%进行拼接,所以我们将汉字"中"转义下便得到了"%E4%B8%AD".

好吧,原理就这些,没有其他的了。

不过,这种方法还有个缺点,那就是只会转义非英文字符,所以当我们需要将英文字符也格式化为UTF8编码时,这个方法是达不到我们需求的,我们还需要额外的将英文字符也给转义下。

那我想要解析回来应该怎么做哪?用decodeURI/decodeURIComponent就可以了。

var codeList = [228, 184, 173];

var code = codeList.map(item => '%'+item.toString(16)).join('');

decodeURI(code); // => 中

好了,到这里本文也就介绍完UTF8的编码了。
希望可以帮助大家了解到UTF-8编码的原理。

以上就是小编为大家带来的通过javascript进行UTF-8编码的实现方法全部内容了,希望大家多多支持三水点靠木~

Javascript 相关文章推荐
js+CSS 图片等比缩小并垂直居中实现代码
Dec 01 Javascript
JQuery 引发两次$(document.ready)事件
Jan 15 Javascript
js获取location.href的参数实例代码
Aug 02 Javascript
轻松实现Bootstrap图片轮播
Apr 20 Javascript
js实现prototype扩展的方法(字符串,日期,数组扩展)
Jan 14 Javascript
jquery实现轮播图效果
Feb 13 Javascript
yarn的使用与升级Node.js的方法详解
Jun 04 Javascript
Javascript别踩白块儿(钢琴块儿)小游戏实现代码
Jul 20 Javascript
Angular客户端请求Rest服务跨域问题的解决方法
Sep 19 Javascript
详解ES6之async+await 同步/异步方案
Sep 19 Javascript
JS双向链表实现与使用方法示例(增加一个previous属性实现)
Jan 31 Javascript
layui使用button按钮 点击出现弹层 弹层中加载表单的实例
Sep 04 Javascript
jQuery实现每隔几条元素增加1条线的方法
Jun 27 #Javascript
jQuery实现查找链接文字替换属性的方法
Jun 27 #Javascript
全面了解javascript三元运算符
Jun 27 #Javascript
javascript运算符——逻辑运算符全面解析
Jun 27 #Javascript
使用vue.js制作分页组件
Jun 27 #Javascript
js编写一个简单的产品放大效果代码
Jun 27 #Javascript
用JS实现轮播图效果(二)
Jun 26 #Javascript
You might like
PHP数组传递是值传递而非引用传递概念纠正
2013/01/31 PHP
php的mssql数据库连接类实例
2014/11/28 PHP
在IE6下发生Internet Explorer cannot open the Internet site错误
2010/06/21 Javascript
面向对象的Javascript之一(初识Javascript)
2012/01/20 Javascript
HTML长文本截取含有HTML代码同样适用的两种方法
2013/07/31 Javascript
关于jquery中全局函数each使用介绍
2013/12/10 Javascript
JavaScript函数定义的常见注意事项小结
2014/09/16 Javascript
JavaScript中数组成员的添加、删除介绍
2014/12/30 Javascript
基于Bootstrap分页的实例讲解(必看篇)
2017/07/04 Javascript
详解React中的组件通信问题
2017/07/31 Javascript
JS实现前端页面的搜索功能
2018/06/12 Javascript
一个Vue视频媒体多段裁剪组件的实现示例
2018/08/09 Javascript
详解基于vue-cli3.0如何构建功能完善的前端架子
2018/10/09 Javascript
开发用到的js封装方法(20种)
2018/10/12 Javascript
nodejs和react实现即时通讯简易聊天室功能
2019/08/21 NodeJs
jQuery 常用特效实例小结【显示与隐藏、淡入淡出、滑动、动画等】
2020/05/19 jQuery
python使用PIL模块实现给图片打水印的方法
2015/05/22 Python
pycharm中连接mysql数据库的步骤详解
2017/05/02 Python
python通过伪装头部数据抵抗反爬虫的实例
2018/05/07 Python
利用python循环创建多个文件的方法
2018/10/25 Python
完美解决Python matplotlib绘图时汉字显示不正常的问题
2019/01/29 Python
Django框架设置cookies与获取cookies操作详解
2019/05/27 Python
Pycharm激活码激活两种快速方式(附最新激活码和插件)
2020/03/12 Python
Django如何批量创建Model
2020/09/01 Python
css3实现信纸/同学录效果的示例代码
2018/12/11 HTML / CSS
html5教程画矩形代码分享
2013/12/04 HTML / CSS
巴西女装购物网站:Eclectic
2018/04/24 全球购物
英国家居用品和家居装饰品购物网站:Cox & Cox
2019/08/25 全球购物
给海归自荐信的建议
2013/12/13 职场文书
学雷锋志愿者活动总结
2014/06/27 职场文书
计划生育证明格式范本
2014/09/12 职场文书
软件研发工程师岗位职责
2014/09/30 职场文书
公安机关党的群众路线教育实践活动剖析材料
2014/10/10 职场文书
学校师德师风整改方案
2014/10/28 职场文书
质检员工作总结2015
2015/04/25 职场文书
nginx配置proxy_pass中url末尾带/与不带/的区别详解
2021/03/31 Servers