通过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 相关文章推荐
HTML-CSS群中单选引发的“事件”
Mar 05 Javascript
javascript 避免闭包引发的问题
Mar 17 Javascript
精选的10款用于构建良好易用性网站的jQuery插件
Jan 23 Javascript
jQuery 对Select的操作备忘记录
Jul 04 Javascript
js获取当前页面路径示例讲解
Jan 08 Javascript
Js与Jq获取浏览器和对象值的方法
Mar 18 Javascript
JavaScript使用键盘输入控制实现数字验证功能
Aug 19 Javascript
jquery实现图片放大点击切换
Jun 06 jQuery
在vue中使用css modules替代scroped的方法
Mar 10 Javascript
javascript将16进制的字符串转换为10进制整数hex
Mar 05 Javascript
jquery实现进度条状态展示
Mar 26 jQuery
基于JavaScript实现随机点名器
Feb 25 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
ThinkPHP之import方法实例详解
2014/06/20 PHP
VB中的RasEnumConnections函数返回632错误解决方法
2014/07/29 PHP
php 使用curl模拟登录人人(校内)网的简单实例
2016/06/06 PHP
Laravel Intervention/image图片处理扩展包的安装、使用与可能遇到的坑详解
2017/11/14 PHP
通过源码解析Laravel的依赖注入
2018/01/22 PHP
Jquery实战_读书笔记2 选择器
2010/01/22 Javascript
一个XML格式数据转换为图表的例子
2010/02/09 Javascript
js中的setInterval和setTimeout使用实例
2014/05/09 Javascript
Bootstrap中CSS的使用方法
2016/02/17 Javascript
基于JQuery实现图片上传预览与删除操作
2016/05/24 Javascript
javascript添加前置0(补零)的几种方法
2017/01/05 Javascript
jQuery中on方法使用注意事项详解
2017/02/15 Javascript
JavaScript登录验证基础教程
2017/11/01 Javascript
基于vue2.0动态组件及render详解
2018/03/17 Javascript
JS实现的简单下拉框联动功能示例
2018/05/11 Javascript
CryptoJS中AES实现前后端通用加解密技术
2018/12/18 Javascript
微信小程序实现图片压缩
2019/12/03 Javascript
使用Python判断IP地址合法性的方法实例
2014/03/13 Python
python开发之thread线程基础实例入门
2015/11/11 Python
Python使用PyQt5/PySide2编写一个极简的音乐播放器功能
2020/02/07 Python
numpy的Fancy Indexing和array比较详解
2020/06/11 Python
Keras 切换后端方式(Theano和TensorFlow)
2020/06/19 Python
python用Configobj模块读取配置文件
2020/09/26 Python
python爬虫工具例举说明
2020/11/30 Python
Scrapy+Selenium自动获取cookie爬取网易云音乐个人喜爱歌单
2021/02/01 Python
CSS3 函数技巧 用css 实现js实现的事情(clac Counters Tooltip)
2017/08/15 HTML / CSS
EJB包括(SessionBean,EntityBean)说出他们的生命周期,及如何管理事务的?
2013/02/17 面试题
自荐信的五个重要部分
2013/10/29 职场文书
技术副厂长岗位职责
2013/12/26 职场文书
党员批评与自我批评
2014/02/12 职场文书
信息与计算机科学职业规划范文:成为一艘有方向的船
2014/09/11 职场文书
党旗在我心中演讲稿
2014/09/15 职场文书
给客户的检讨书
2014/12/21 职场文书
网络管理员岗位职责
2015/02/12 职场文书
新闻稿格式范文
2015/07/18 职场文书
mysql查询结果实现多列拼接查询
2022/04/03 MySQL