UTF8和UNICODE的关系及转换规则(字库篇一)
UNICODE
Unicode
是ASCII
和Latin-1
的超集,并支持地球上几乎所有的语言。
UTF-8
UTF-8(UTF8-bit Unicode Transformation Format)
是一种针对Unicode的可变长度字符编码,也是一种前缀码。
它可以用来表示Unicode标准中的任何字符,且其编码中的第一个字节仍与ASCII兼容
,这使得原来处理ASCII字符的软件无须或只须做少部分修改,即可继续使用。因此,它逐渐成为电子邮件、网页及其他存储或发送文字的应用中,优先采用的编码
。
目前大部分的网站,都是使用的UTF-8编码。
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
具体请看图片:
因为英文和英文字符的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个字节如何得到哪?
这就需要设计到补码,具体补码逻辑如下:
好吧,我知道这个图你们也看不明白,还是我来讲吧!
具体的补位码如下,"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按照从前到后的顺序,依次补到0xxxxxxx的空位中,得到01000001
6、将01000001转为字符串,得到"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编码的原理。
UTF8和UNICODE的关系及转换规则(字库篇一)相关推荐
- Unicode,UTF-32,UTF-16,UTF-8到底是啥关系?
编码的目的,就是给抽象的字符赋予一个数值,好在计算机里面表示.常见的ASCII使用8bit给字符编码,但是实际只使用了7bit,最高位没有使用,因此,只能表示128个字符:ISO-8859-1(也叫L ...
- ascii unicode utf8 gkb之间的关系
Unicode UTF GBK之间的关系,在python中如何转化 2008-07-03 14:48 Unicode是一个字符集,不是一种编码,她只是定义了一个字符空间,把字符集中的字符映射到了相应的 ...
- 介绍一下unicode,ansi,utf-8,unicode big endian编码
介绍一下unicode,ansi,utf-8,unicode big endian编码 很久很久以前,有一群人,他们决定用8个可以开合的晶体管来组合成不同的状态,以表示世界上的万物.他们看到8个开关状 ...
- 字符编码总结(UTF-8,UNICODE)
UTF-8是Unicode的一种实现方式,也就是它的字节结构有特殊要求,所以我们说一个汉字的范围是0X4E00到0x9FA5,是指unicode值,至于放在utf-8的编码里去就是由三个字节来组织,所 ...
- c++ unicode转换中文_彻底弄懂UTF-8、Unicode、宽字符、locale
结论 宽字符类型wchar_t locale 为什么需要宽字符类型 多字节字符串和宽字符串相互转换 最近使用到了wchar_t类型,所以准备详细探究下,没想到水还挺深,网上的资料大多都是复制粘贴,只有 ...
- 编码学习——UTF-8与Unicode互转具体流程
了解最早以前的只有英文数字字符.控制代码.空格与二进制之间的关系--ASCII码 在计算机内部,所有数据都是使用二进制存储.每一个二进制都代表一位(bit),这一位数有0和1两种状态,在ASCII中是 ...
- AL32UTF8/UTF8(Unicode)数据库字符集含义 (文档 ID 1946289.1)
AL32UTF8/UTF8(Unicode)数据库字符集含义 (文档 ID 1946289.1) 适用于: Oracle Database Cloud Schema Service - 版本 N/A ...
- UTF8、unicode、GB2312、ASCII区别
简述: ASCII和Unicode都是编码规定,只是一个符号集 在ASCII码中,一个汉字占2个字节(一个字符占一个字节) 在Unicode编码中,一个汉字占2个字节(一个字符同样占两个字节,所以JA ...
- UTF-8,Unicode,GB2312编码转换(C语言)
UTF-8,Unicode,GB2312编码转换(C语言) 最近在做MQTT客户端的时候,遇到需要将输入的GB2312中文转换为UTF8的问题,这边做一个整理. UTF-8转GB2312 代码: /* ...
最新文章
- java程序员学C#基本语法两个小时搞定(对比学习)
- JavaSE、JavaEE与Spring的概念和异同点剖析
- 个人博客作业第三周--必应词典分析
- nodejs 从TCP套接字读取并解析数据
- macos sierra 引导镜像_真想不到,在win10上可以制作苹果macOS启动U盘
- java 修改txt_Java实现批量修改txt文件名称的方法示例
- 一个创业公司CEO的85条感悟
- Vue 系列二 之 猛龙行动之绝密代码
- 7x android 8,内测开启 华为荣耀畅玩7X升级Android 8.0
- JS rgba颜色转16进制
- smtp邮件服务器的作用,smtp服务器是什么意思(smtp服务器作用及使用指南)
- 微粒群算法(PSO)
- 数据挖掘:实用案例分析
- MeasureSpec
- tailf追踪日志文件
- 铁蛋白-AHLL纳米颗粒|人表皮生长因子-铁蛋白重链亚基纳米粒子(EGF-5Cys-FTH1)|铁蛋白颗粒包载氯霉素Chloramphenicol-Ferritin
- flask返回本地文件到服务器,Flask返回静态文件
- 【金融项目】尚融宝项目(四)
- 数字变成大写的类,把人民币转化为大写汉字
- Go学习笔记_环境搭建
热门文章
- 软件测试职业发展方向(不要迷茫了,赶紧卷起来)
- python列表习题
- Openstack Horizon 可插拔Panels 和 Groups
- JavaScript 算法 -- 贪心算法
- 微软office 2016_如何升级到Microsoft Office 2016
- python nonlocal叠加_python nonlocal 的具体原理
- 【Java扫盲篇】今天用人话给你讲清楚:进程、线程、并发、并行、高并发?
- matlab一次二阶矩法正态分布,一次二阶矩法.ppt
- win10下编译C代码:cmd 命令行 + notepad 记事本
- Android studio 莫名出现 D8: java.lang.NullPointerException解决方法