字符编码

简介

  1. 起初再考虑写不写这篇文章,感觉这篇文章比较枯燥乏味,而且自己感觉也没理解的太透彻,就把理解的记录下来,所以这是纪念版的
  2. 前方高能,非战斗人员请迅速撤离,我要开始装逼了。

Go hard or go home 要么全力以赴,要么走人 No person has the right to rain on your dreams,you do it yourself. 没有人有权利给你的梦想泼冷水,只有你自己给自己的梦想泼冷水

看到这样的文字是不是很励志?那换一种方式你还会这样想吗? 16进制版:
复制代码

476f2068617264206f7220676f20686f6d652089814e485168529b4ee58d742c89814e488d704eba20a4e6f20706572736f6e20206861732074686520726967687420746f207261696e206f6e20796f757220647265616d732c796f7520646f20697420796f757273656c662e206ca167094eba6709674352297ed94f60768468a660f36cfc51b76c342c53ea67094f6081ea5df17ed981ea5df1768468a660f36cfc51b76c34

然而他的字符编码是GB2312的,叫我转化成易懂的字符串,当时我就懵b了。因为当时我对字符编码一窍不通,然后就网上,查啊查,最后终于想到了解决方案
复制代码

几个值的深思的问题

  1. 什么是字符?

字符是各种文字和符号的总称,包括各个国家文字、标点符号、图形符号、数字等。

  1. 什么是字符集?

字符集是多个字符的集合,字符集种类较多,每个字符集包含的字符个数不同,常见字符集有:ASCII字符集、ISO 8859字符集、GB2312字符集、BIG5字符集、GB18030字符集、Unicode字符集等

  1. 什么是字符编码?

1、 计算机要准确的处理各种字符集文字,需要进行字符编码,以便计算机能够识别和存储各种文字。 2、 字符编码(encoding)和字符集不同。字符集只是字符的集合,不一定适合作网络传送、处理,有时须经编码(encode)后才能应用。如Unicode可依不同需要以UTF-8、UTF-16、UTF-32等方式编码。 3、字符编码就是以二进制的数字来对应字符集的字符。 因此,对字符进行编码,是信息交流的技术基础。

  1. 概括

1、使用哪些字符。也就是说哪些汉字,字母和符号会被收入标准中。所包含“字符”的集合就叫做“字符集”。 2、规定每个“字符”分别用一个字节还是多个字节存储,用哪些字节来存储,这个规定就叫做“编码”。 3、各个国家和地区在制定编码标准的时候,“字符的集合”和“编码”一般都是同时制定的。因此,平常我们所说的“字符集”,比如:GB2312, GBK, JIS 等,除了有“字符的集合”这层含义外,同时也包含了“编码”的含义。 4、注意:Unicode字符集有多种编码方式,如UTF-8、UTF-16等;ASCII只有一种;大多数MBCS(包括GB2312,GBK)也只有一种。

  1. 有趣的例子

1、在显示器上看见的文字、图片等信息在电脑里面,其实并不是我们看见的样子,即使你知道所有信息都存储在硬盘里,把它拆开也看不见里面有任何东西,只有些盘片。假设,你用显微镜把盘片放大,会看见盘片表面凹凸不平,凸起的地方被磁化,凹的地方是没有被磁化;凸起的地方代表数字1,凹的地方代表数字0。硬盘只能用0和1来表示所有文字、图片等信息。 2、那么字母”A”在硬盘上是如何存储的呢?可能小张计算机存储字母”A”是1100001,而小王存储字母”A”是11000010,这样双方交换信息时就会误解。比如小张把1100001发送给小王,小王并不认为1100001是字母”A”,可能认为这是字母”X”,于是小王在用记事本访问存储在硬盘上的1100001时,在屏幕上显示的就是字母”X”。也就是说,小张和小王使用了不同的编码表。小张用的编码表是ASCII,ASCII编码表把26个字母都一一的对应到2进制1和0上;小王用的编码表可能是EBCDIC,只不过EBCDIC编码与ASCII编码中的字母和01的对应关系不同。一般地说,开放的操作系统(LINUX 、WINDOWS等)采用ASCII 编码,而大型主机系统(MVS 、OS/390等)采用EBCDIC 编码。在发送数据给对方前,需要事先告知对方自己所使用的编码,或者通过转码,使不同编码方案的两个系统可沟通自如。

  1. 这个例子说明了三点

1、不管是任何文字图片等,最后都会以二进制的形式储存到电脑的磁盘中(比如记事本A.txt,内容为"ABC"文件,在此磁盘中表现的就是01 01这种二进制形式) 盘片表面凹凸不平,凸起的地方被磁化,凹的地方是没有被磁化,凸起的地方代表数字1,凹的地方代表数字0。硬盘只能用0和1来表示所有文字、图片等信息。是的 很强势 2、 任何文件要储存到电脑中,都会事先进行编码,然后储存到电脑的磁盘中,比如A.txt文件,默认编码为ANSI编码,也可以编码为UTF-8,然而不同的编码方式 对应着计算机用一个字节还是多个字节存储,用哪些字节来存储。 3、在双方数据进行通讯时,要么就保证发送方和接受方的数据编码是相同,要么就是其中一方需要转码

  1. 什么是字节和位?

字节byte和位bit是电脑里的数据量单位。 1.按计算机中的规定,一个英文的字符占用一个字节,而一个汉字以及汉字的标点符号、字符都占用两个字节。 2.1个字节等于8位 1byte=8bit 3.1bit在磁盘中以二进制01的形式保存 凸起的地方代表数字1,凹的地方代表数字0

字符编码种类

ASCII

ASCII码是西欧编码的方式,采取7位编码,所以是2^7=128,共可以表示128个字符,包括34个字符,(如换行LF,回车CR等),其余94位为英文字母和标点符号及运算符号等。

重点:

字符集:从符号(NUL="/0"=“空操作字符”)到“Z”再到“DEL”符号 字符编码范围:二进制:00000000——01111111 十进制:0-127 占用字节:1字节 8bit 盘片储存方式:凹凹凹凹凹凹凹凹——凸凸凸凸凸凸凸凸

注:NUL:‘\0'是一个ASCII码为0的字符,从ASCII码表中可以看到ASCII码为0的字符是“空操作字符”,它不引起任何控制动作,也不是一个可显示的字符。

但我们发现ASCII码是没有中文编码的,显然在天朝是不够用的,于是GB2312诞生了。 ###GB2321 GB2312 是对 ASCII 的中文扩展。兼容ASCII。

编码规定: 编码小于127的字符与ASCII编码相同, 特性:两个大于127的字符连在一起时,就表示一个汉字,前面的一个字节(称之为高字节)从0xA1用到0xF7,后面一个字节(低字节)从0xA1到0xFE,这样我们就可以组合出大约7000多个简体汉字了。

字符集:从符号(NUL="/0"=“空操作字符”)到“Z”到“齄"(简体中文) 字符编码范围:16进制:0x0000-(中间有一部分是未使用的)-0xF7FE 占用字节:英文 1字节 8bit 盘片储存方式:凹凹凹凹凹凹凹凹——凸凸凸凸凸凸凸凸 中文 2字节 16bit 凹凹凹凹凹凹凹凹凹凹凹凹凹凹凹凹——...

GBK

GBK 兼容ASCLL 兼容 GB2312 是GB2312的扩展 但是中国的汉字太多了,我们很快就就发现有许多人的人名没有办法在这里打出来,不得不继续把 GB2312 没有用到的码位找出来用上。后来还是不够用,于是干脆不再要求低字节一定是127号之后的内码,只要第一个字节是大于127就固定表示这是一个汉字的开始,不管后面跟的是不是扩展字符集里的内容。结果扩展之后的编码方案被称为 “GBK” 标准,GBK 包括了 GB2312 的所有内容,同时又增加了近20000个新的汉字(包括繁体字)和符号。 ###Unicode Unicode是国际组织制定的可以容纳世界上所有文字和符号的字符编码方案。 目前的Unicode字符分为17组编排,0x0000至0x10FFFF,每组称为平面(Plane),而每平面拥有65536个码位,共1114112个。然而目前只用了少数平面。UTF-8、UTF-16、UTF-32都是将数字转换到程序数据的编码方案。

UTF-8

UTF-8以字节为单位对Unicode进行编码。从Unicode到UTF-8的编码方式如下: UTF-8的特点是对不同范围的字符使用不同长度的编码。对于0x00-0x7F之间的字符,UTF-8编码与ASCII编码完全相同。UTF-8编码的最大长度是6个字节。从上表可以看出,6字节模板有31个x,即可以容纳31位二进制数字。Unicode的最大码位0x7FFFFFFF也只有31位。 例1:“汉”字的Unicode编码是0x6C49。0x6C49在0x0800-0xFFFF之间,使用用3字节模板了:1110xxxx 10xxxxxx 10xxxxxx。将0x6C49写成二进制是:0110 1100 0100 1001, 用这个比特流依次代替模板中的x,得到:11100110 10110001 10001001,即E6 B1 89。 举一个例子:It's 知乎日报

你看到的unicode字符集是这样的编码表:

I 0049 t 0074 ' 0027 s 0073 0020 知 77e5 乎 4e4e 日 65e5 报 62a5 每一个字符对应一个十六进制数字。

计算机只懂二进制,因此,严格按照unicode的方式(UCS-2),应该这样存储:

I 00000000 01001001 t 00000000 01110100 ' 00000000 00100111 s 00000000 01110011 00000000 00100000 知 01110111 11100101 乎 01001110 01001110 日 01100101 11100101 报 01100010 10100101 这个字符串总共占用了18个字节,但是对比中英文的二进制码,可以发现,英文前9位都是0!浪费啊,浪费硬盘,浪费流量。

怎么办?

UTF

UTF-8是这样做的:

  1. 单字节的字符,字节的第一位设为0,对于英语文本,UTF-8码只占用一个字节,和ASCII码完全相同;
  1. n个字节的字符(n>1),第一字节的前n位设为1,第n+1位设为0,后面字节的前两位都设为10,这n个字节的其余空位填充该字符unicode码,高位用0补足。

这样就形成了如下的UTF-8标记位:

高位字节 低位字节 低位字节 低位字节 低位字节 低位字节
0xxxxxxx
110xxxxx 10xxxxxx
1110xxxx 10xxxxxx 10xxxxxx
11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
... ....

>比如"知"字 在Unicode中占用两个字节,那么第一字节(我叫它高位字节)的前两位设位1,第三位设为10,后面低位字节设为前两位设为10, "知"→ 11100111 10011111 10100101 怎么知道“知”字占用两个字节的?首先要知道Unicode字符集中,“知”字的编码为77e5,然后转化为二进制流01110111 11100101的bit,每8bit等于1byte 所以就占两个字节 >于是,”It's 知乎日报“就变成了: I 01001001 t 01110100 ' 00100111 s 01110011 00100000 知 11100111 10011111 10100101 乎 11100100 10111001 10001110 日 11100110 10010111 10100101 报 11100110 10001010 10100101 和上边的方案对比一下,英文短了,每个中文字符却多用了一个字节。但是整个字符串只用了17个字节,比上边的18个短了一点点。 剧透:一切都是为了节省你的硬盘和流量。

一图解忧愁

1.从这个可以看出,同样的字符集,但unicode编码和gbk编码是不同的。,所以unicode字符集不兼容gbk字符集 2.只要知道unicode字符集的编码表,就可以用UTF8编码规则找到UTF-8对应的汉字编码


解决问题

从上面的内容了解了字符编码以后,以后遇到相关的字符编码问题的时候至少有解决的思路,而不是一头雾水

分析

NodeJS服务端环境下 476f2068617264206f7220676f20686f6d652089814e485168529b4ee58d742c89814e488d704eba20a4e6f20706572736f6e20206861732074686520726967687420746f207261696e206f6e20796f757220647265616d732c796f7520646f20697420796f757273656c662e206ca167094eba6709674352297ed94f60768468a660f36cfc51b76c342c53ea67094f6081ea5df17ed981ea5df1768468a660f36cfc51b76c34 容易产生误区: 这个问题的情况并不是字符乱码问题,而只是怎样解析16进制gb2312字符,只是利用了字符编码的原理。 1.我接受的是gb2312格式的数据,但是这里并没有乱码,因为服务器发过来的是数字和英文,gb2312是兼容ASCII的。 2.我设置了(接受响应数据编码格式)response.setEncoding('gb2312');即使我不设置响应格式,nodejs默认识utf-8的,utf-8和gbk都是兼容ASCII,也是就是支持英文和数字

var http=require('http');
var Iconv = require('iconv-lite');//转码数据
var GetHttp=function(options,callback){
var AllData="";
try{
var GetReq = http.request(options, function (res) {  console.log('STATUS: ' + res.statusCode);res.setEncoding('gb2312');
if(res.statusCode==200){  res.on('data', function (chunk) { AllData+=chunk;}).on('end',function(){callback(200,AllData);})
}else{
callback(500,'error');
}
console.log(AllData);
});
GetReq.on('error',function(err){callback(500,err)});
GetReq.end();
}catch(error){
callback(500,error);
}
}exports.GetHttp=GetHttp;
复制代码

开始问题分析: 1.字符集分析:gb2312支持数字和英文和6000+汉字 2.编码分析:英文占一个字节,中文占两个字节(这就是问题)

//1.fromCharCode() 可接受一个指定的 Unicode 值,然后返回一个字符串。但我们的数据是gb2312的编码数据,然而gbk和unicode的编码方式又不一样,所以解析出来的数据会乱码
//2.利用下面的代码,中文也会乱码,因为英文占1个字节,中文占2个字节,1个字节是8个二进制流的bit=2个16进制流的bit,而中文=4个16进制流的bit,下面的代码相当于把1个16进制的数转为字符
function HexTostring(s) {var r = "";for (var i = 0; i < s.length; i += 2) { var sxx = parseInt(s.substring(i, i + 2), 16); r += String.fromCharCode(sxx); }return r;
}
复制代码

这时就要想到,中文汉子对照表:

解决方案

  1. 首先把汉子编码对照表存入以存入数据库(mongodb)

  2. 获取,并以key=gbk16进制编码 value=汉子的形式存下来

  var dicUniCodeCN=new Array();DBTool.FindData('mongodb://数据库地址/数据库名','unicodeCN',{},function(Docs){if (Docs.length>0) {for (var i = 0; i < Docs.length; i++) {dicUniCodeCN[Docs[i].gbk16.toString().toUpperCase()]=Docs[i].CN;};}});
复制代码

3.特性:gb2312的高位字节如果大于127(ASCII),就为中文,只有gb2312具有这个特性

 var simpleCNStr="";for (var j = 0; j < hexData.length; j += 2){
//高位字节>127为中文
var strHex=hexData.substring(j,j+2);
console.log(parseInt("0x"+strHex,16));if (parseInt("0x"+strHex,16)>127) {strHex=hexData.substring(j,j+4);j+=2;simpleCNStr+=dicUniCodeCN[strHex];
}else{simpleCNStr+=String.fromCharCode(parseInt(strHex,16));
}
}复制代码

4.如果想兼容utf-8和unicode和gbk,那么可以4位16进制的字符截取,如果大于127,那么默认为中文,否则就是英文或字符或数字

 var simpleCNStr="";for (var j = 0; j < hexData.length; j += 4){
//4位截取,大于127的为中文
var strHex=hexData.substring(j,j+4);
console.log(parseInt("0x"+strHex,16));if (parseInt("0x"+strHex,16)>127) {
//不想写了
}else{
//待续 你们写吧...
}
}
复制代码

题外话-关于parseInt(string, radix)

parseInt("10");           //返回 10
parseInt("19",10);        //返回 19 (10+9)
parseInt("11",2);     //返回 3 (2+1)
parseInt("17",8);     //返回 15 (8+7)
parseInt("1f",16);        //返回 31 (16+15)
parseInt("010");      //未定:返回 10 或 8
复制代码

这个函数是把数字或进制字符都转为10进制的数字,第二个参数radix表示的是第一个参数string的类型(10进制,2进制,8进制,16进制),我之前很白菜的理解为我想把第一个参数string转化成16进制。哎,我还是太年轻啊

转载于:https://juejin.im/post/5c74b6f7e51d45454054af4a

深入理解-字符编码ASCII,GB2312,GBK,Unicode,UTF-8相关推荐

  1. ASCII, GB2312, GBK, Unicode, UTF8之间的区别和联系

    原文链接:https://zhuanlan.zhihu.com/p/258345888 感谢原作者的分享~本博客仅仅是为了做笔记 计算机是美国人发明的, 早期在处理文字方面, 美国人很自然地只考虑处理 ...

  2. 常用字符集(ASCII,ISO8859-1,GB2312,GBK,Unicode)和字符编码(UTF-8,UTF-16)

    转自:https://blog.csdn.net/wn084/article/details/80363792 参考:https://blog.csdn.net/halchan/article/det ...

  3. 【JAVA编码专题】JAVA字符编码系列一:Unicode,GBK,GB2312,UTF-8概念基础

    这两天抽时间又总结/整理了一下各种编码的实际编码方式,和在Java应用中的使用情况,在这里记录下来以便日后参考. 为了构成一个完整的对文字编码的认识和深入把握,以便处理在Java开发过程中遇到的各种问 ...

  4. Computer:字符编码(ASCII编码/GBK编码/BASE64编码/UTF-8编码)的简介、案例应用(python中的编码格式及常见编码问题详解)之详细攻略

    Computer:字符编码(ASCII编码/GBK编码/BASE64编码/UTF-8编码)的简介.案例应用(python中的编码格式及常见编码问题详解)之详细攻略 目录 符串编码(ASCII编码/GB ...

  5. 字符编码ASCII、Unicode 、UTF-8 及实例汉字与Unicode码的相互转化

    字符编码ASCII.Unicode .UTF-8 及实例汉字与Unicode码的相互转化 ASCII 码 我们知道,计算机内部,所有信息最终都是一个二进制值.每一个二进制位(bit)有0和1两种状态, ...

  6. 【JAVA编码】 JAVA字符编码系列二:Unicode,ISO-8859,GBK,UTF-8编码及相互转换

    http://blog.csdn.net/qinysong/article/details/1179489 这两天抽时间又总结/整理了一下各种编码的实际编码方式,和在Java应用中的使用情况,在这里记 ...

  7. 【字符编码】彻底理解字符编码

    一.前言 在解决昨天的问题时,又引出了很多新的问题,如为什么要进行编码,这些编码的关系如何,如ASCII,IOS-8859-1,GB2312,GBK,Unicode之间的关系,笔者想要彻底理解字符编码 ...

  8. 编码标准-GB2312 GBK GB18030

    关于 ASCII编码 可以查看我的另外一篇博客 编码标准-ASCII 关于 Unicode 可以参考我的另外一篇博客 Unicode 编码标准-GB2312 GBK GB18030 基本概念 区位码 ...

  9. 计算机字符编码——ASCII码和常用编码

    计算机字符编码--ASCII码和常用编码 ASCII码 基本介绍 上个世纪60年代, 美国制定了一套字符编码, 对英语字符与二进制位之间的关系, 做了统一规定,这被称为ASCII码. ASCII码一共 ...

最新文章

  1. 2019BATJ面试题汇总详解:MyBatis+MySQL+Spring+Redis+多线程
  2. 35岁前十件事该做好
  3. python数据处理_时间序列数据处理python 库
  4. DB2的日志理解难点
  5. linux 应用层gpio中断_如何在嵌入式Linux中检测GPIO线路上的中断?
  6. 转 JavaScript传值及.Net传值方式总结
  7. Day Tips:关于搜索小问题
  8. 新冠全球蔓延,AI+大数据拿什么拯救全人类? | AI 技术生态论
  9. 基于麻雀算法优化的核极限学习机(KELM)回归预测 -附代码
  10. 微信小程序修改BUTTON点击态样式
  11. 03 tcl提取文件路径操作
  12. 安全性(security)度量
  13. acwing 合唱队形
  14. moment.js 计算当前一周、一月对应日期
  15. 语义分割各种评价指标实现
  16. SecurityException: Uid 0312 does not have permission content://com.android.providers...
  17. 利用计算机网络犯罪案例,网络犯罪指导性案例实务指引
  18. 28岁程序员期权过亿从字节退休,当事人:同级的张天一比我财富自由多了
  19. php面向对象三大特性,PHP面向对象的三大特性之一封装性
  20. GeoMesa HBase 安装及问题解决:

热门文章

  1. linux中分区详细步骤,Linux下硬盘分区的具体步骤
  2. 阿里云李飞飞:数据库将迎来“四化”趋势
  3. 如何用照片制作短视频,怎么用照片制作小视频
  4. 2.基于原型的聚类方法
  5. v16_G120调试电机优化编程
  6. 华为桌面云技术与应用
  7. python自动下载阿里云数据库数据_脚本自动下载阿里云每日备份数据库镜像
  8. PPT制作树状结构图
  9. 关于删除重建ORACLE database的小笔记
  10. ChinaJoy直击:AMD显卡树立1080p高帧率、高保真PC游戏新标准