1. 机器学习+首页
  2. 编程语言
  3. PYTHON

python日记第二章:二进制、字符编码、十六进制转换

终于要讲2进制啦,讲之前,我们先讲个小故事,

秒懂二进制

大家知道古时候的中国是如何通信的么?

假如,战国时期两个国家要打仗了,我们垒了城墙,每隔一段就有兵镇守,现在有人来攻打我们了,然后我们是不是得通知其他人有人来打我们来了?怎么通知?

  1. 派个人跑着去?等人回来,仗打完了
  2. 飞鸽传书?不靠谱,鸽子会被敌人射下来做烧烤
  3. 点狼烟信号,可行

好了,现在有5000精兵来打你了,你点了根狼烟搬救兵,从东边来了10个人,西边来了10个人,20个人来了,和你们一起战死了。

这怎么办?

我们不能这么保守了,只要我一点狼烟说有人来打我们了,先来他10000人,结果来了200个敌人,我们呼啦啦来一大堆人,是不是浪费资源啊?

我们是不是除了告诉人家要打仗了,还得告诉别人来了多少人啊?那我们怎么告诉?

来一个人点一根?来了5000人,点5000根,不用打了,自己给自己烧死了

那好我们就约定,来10个人点1根,来100个人点2根,来1000个人点3根,来5000个点4根,来10000个点5根。。。以此类推,恭喜你, 这样确实就能解决问题啦,粗略的能告诉友军来了多少敌人。

但现在友军将领提了一个变态的要求,你必须精确的告诉他一共来了多少敌人,他才安排来救援。 如何精确传送到底有多少个敌人?

各位同学可以自行思考研究5分钟,但我估计你想不出来哈哈。

好了,现在来看看我的方法。。。

假如我们有20个狼烟孔,狼烟孔点燃了代表有人,没点燃代表没人。

这时候,1个敌人来了,点1根狼烟

现在2个敌人来了,怎么办?再点一根狼烟,把20根狼烟都点上能表示20个人。。。这肯定不行。我们这样,把

第一个狼烟孔灭掉,点燃第二个,这样只点燃第二个孔就代表两个人

现在3个敌人来了,怎么办?把第一个狼烟孔点着了就表示3个人

那如果来了4个人敌人,现在有两根狼烟都点着了只能表示3个人,表示4个人,做得到么?臣妾做不到啊~~~

不过还记得么?之前使用2根狼烟只能表示2个人,现在我们通过一些奇淫巧技是不是表达了4种状态(0,1,2,3)啦。。。

看看眼下这4个可恶的敌人吧,咱们用这两根狼烟已经装不下他们了,所以我们只好再点一根,同时我们还要灭掉前面的两根,因为第三根这一根狼烟就可以表示4个敌人

接下来我们以此类推,烟不够了就往后多点一根,最终就出现这样的情况了,各位算算这是多少敌人?

很简单,把红色柱子代表的值加起来就行了对吧,一共247个敌人。

到此,友军将领的变态需求终于满足啦。。。

最后补充下,算敌人个数时,你要把每个红柱子加起来,柱子越多,算的越慢。 其实有快速算法,你发现没有,每根柱子所代表的值 就是此柱及其前面柱子的多少次方。

好,同学们,快帮我算出来,如果来61352个敌人的话,狼烟如何排列?

二进制定义

二进制是计算技术中广泛采用的一种数制。二进制数据是用0和1两个数码来表示的数。它的基数为2,进位规则是“逢二进一”,借位规则是“借一当二”,由18世纪德国数理哲学大师莱布尼兹发现。当前的计算机系统使用的都是二进制系统,数据在计算机中主要是以补码的形式存储的。计算机中的二进制则是一个非常微小的开关,用“开”来表示1,“关”来表示0。

我们发现刚刚我们讲述的狼烟的故事和现在这个新理论出奇相似。假设狼烟点燃用1表示,狼烟灭掉用0表示,那么刚刚我们用狼烟表示百万雄师的理论就可以用在计算机上,这种表示数字的方式就叫做二进制。

你可能会觉得发明计算机的人思路轻奇,为什么要多此一举的用这种方式来表达数字,但事实上计算机不像我们这样智能,CPU是一个包含上亿个精巧的晶体管的芯片集合,晶体管表达感情的方式很简单,就是通过高低电压(有电没电),低电压的时候表示0,高电压的时候表示1,因此最终能让计算机理解的就只有0和1而已。

二进制与十进制转换

其实刚刚在无形中我们已经将10进制转换成2进制了,现在我们要再总结一遍。

刚才我们已经发现,二进制的第n位代表的十进制值都刚好遵循着2的n次方这个规律

填位大法:

先把他们代表的值依次写出来,然后再根据10进制的值把数填到相应位置,就好了~~~

十进制转二进制方法相同,只要对照二进制为1的那一位对应的十进制值相加就可以了。

字符编码-中文是如果显示的

通过上一节讲的二进制的知识,大家已经知道计算机只认识二进制,生活中的数字要想让计算机理解就必须转换成二进制。十进制到二进制的转换只能解决计算机理解数字的问题,那么文字要怎么让计算机理解呢?

于是我们就选择了一种曲线救国的方式,既然数字可以转换成十进制,我们只要想办法把文字转换成数字,这样文字不就可以表示成二进制了么?

可是文字应该怎么转换成数字呢?就是强制转换啊,简单粗暴呀。 我们自己强行约定了一个表,把文字和数字对应上,这张表就相当于翻译,我们可以拿着一个数字来对比对应表找到相应的文字,反之亦然。

ASCII码

这张表就是计算机显示各种文字、符号的基石呀

ASCII(American Standard Code for Information Interchange,美国信息交换标准代码)是基于拉丁字母的一套电脑编码系统,主要用于显示现代英语和其他西欧语言。它是现今最通用的单字节编码系统,并等同于国际标准ISO/IEC 646。

由于计算机是美国人发明的,因此,最早只有127个字母被编码到计算机里,也就是大小写英文字母、数字和一些符号,这个编码表被称为ASCII编码,比如大写字母A的编码是65,小写字母z的编码是122。后128个称为扩展ASCII码。

那现在我们就知道了上面的字母符号和数字对应的表是早就存在的。那么根据现在有的一些十进制,我们就可以转换成二进制的编码串。

比如

一个空格对应的数字是0          翻译成二进制就是0(注意字符'0'和整数0是不同的)
一个对勾√对应的数字是251       翻译成二进制就是11111011

提问:假如我们要打印两个空格一个对勾 写作二进制就应该是 0011111011, 但是问题来了,我们怎么知道从哪儿到哪儿是一个字符呢?

论断句的重要性与必要性:

上次在网上看到个新闻,讲是个小偷在上海被捕时高喊道:“我一定要当上海贼王!”

正是由于这些字符串长的长,短的短,写在一起让我们难以分清每一个字符的起止位置,所以聪明的人类就想出了一个解决办法,既然一共就这255个字符,那最长的也不过是11111111八位,不如我们就把所有的二进制都转换成8位的,不足的用0来替换。

这样一来,刚刚的两个空格一个对勾就写作000000000000000011111011,读取的时候只要每次读8个字符就能知道每个字符的二进制值啦。

在这里,每一位0或者1所占的空间单位为bit(比特),这是计算机中最小的表示单位

每8个bit组成一个字节,这是计算机中最小的存储单位(毕竟你是没有办法存储半个字符的)orz~

bit           位,计算机中最小的表示单位
8bit = 1bytes 字节,最小的存储单位,1bytes缩写为1B
1KB=1024B
1MB=1024KB
1GB=1024MB
1TB=1024GB
1PB=1024TB
1EB=1024PB
1ZB=1024EB
1YB=1024ZB
1BB=1024YB

GB2312 & GBK

英文问题是解决了, 我们中文如何显示呢? 美国佬设计ASSCII码的时候应该是没考虑中国人有一天也能用上电脑, 所以根本没考虑中文的问题,上世界80年代,电脑进入中国,把砖家们难倒了,妈的你个一ASSCII只能存256个字符,我常用汉字就几千个,怎么玩???勒紧裤腰带还苏联贷款的时候我们都挺过来啦,这点小事难不到我们, 既然美帝的ASCII不支持中文,那我们自己搞张编码表不就行了, 于是我们设计出了GB2312编码表,长成下面的样子。一共存了6763个汉字。

这个表格比较大,像上面的一块块的文字区域有72个,这导致通过一个字节是没办法表示一个汉字的(因为一个字节最多允许256个字符变种,你现在6千多个,只能2个字节啦,2**16=65535个变种)。

有了gb2312,我们就能愉快的写中文啦。

但我们写字竟然会出现中英混杂的情况,比如“我是小猿圈,我的英文名叫Apeland.”, 这种你怎么办?这就要求你必须在gb2312里同时支持英文,但是还不能是2个字节表示一个英文字母。人家ASCII用一个字符,你用2个,那一个2mb大小的英文文档只要一改编码,就立刻变成4mb, 太坑爹,中国人你有钱也不能这么造呀。 所以中国砖家们又通过神奇手段兼容了ASSCII, 即遇到中文用2个字节,遇到英文直接用ASCII的编码。怎么做到的呢?

如何区别连在一起的2个字节是代表2个英文字母,还是一个中文汉字呢? 中国人如此聪明,决定,如果2个字节连在一起,且每个字节的第1位(也就是相当于128的那个2进制位)如果是1,就代表这是个中文,这个首位是128的字节被称为高字节。 也就是2个高字节连在一起,必然就是一个中文。你怎么如此笃定?因为0-127已经表示了英文的绝大部分字符,128-255是ASCII的扩展表,表示的都是极特殊的字符,一般没什么用。所以中国人就直接拿来用了。

自1980年发布gb2312之后,中文一直用着没啥问题,随着个人电脑进入千家万户,有人发现,自己的名字竟然打印不出来,因为起的太生僻了。

于是1995年, 砖家们又升级了gb2312, 加入更多字符,连什么藏语、维吾尔语、日语、韩语、蒙古语什么的统统都包含进去了,国家统一亚洲的野心从这些基础工作中就可见一斑哈。 这个编码叫GBK,一直到现在,我们的windows电脑中文版本的编码就是GBK.

编码混战时代

中国人在搞自己编码的同时,世界上其它非英语国家也得用电脑呀,于是都搞出了自己的编码,你可以想得到的是,全世界有上百种语言,日本把日文编到Shift_JIS里,韩国把韩文编到Euc-kr里,

各国有各国的标准,就会不可避免地出现冲突,结果就是,在多语言混合的文本中,显示出来会有乱码。之前你从玩个日本游戏,往自己电脑上一装,就显示乱码了。

这么乱极大了阻碍了不同国家的信息传递,于是联合国出面,发誓要解决这个混乱局面。

因此,Unicode应运而生。Unicode把所有语言都统一到一套编码里,这样就不会再有乱码问题了。Unicode 2-4字节 已经收录136690个字符,并还在一直不断扩张中…

Unicode标准也在不断发展,但最常用的是用两个字节表示一个字符(如果要用到非常偏僻的字符,就需要4个字节)。现代操作系统和大多数编程语言都直接支持Unicode

Unicode有2个特点:

  1. 支持全球所有语言
  2. 可以跟各种语言的编码自由转换,也就是说,即使你gbk编码的文字 ,想转成unicode很容易。

为何unicode可以跟其它语言互相转换呢? 因为有跟所有语言都有对应关系哈,这样做的好处是可以让那些已经用gbk或其它编码写好的软件容易的转成unicode编码 ,利于unicode的推广。 下图就是unicode跟中文编码的对应关系

UTF-8

新的问题又出现了:如果统一成Unicode编码,乱码问题从此消失了。但是,如果你写的文本基本上全部是英文的话,用Unicode编码比ASCII编码需要多一倍的存储空间,由于计算机的内存比较大,并且字符串在内容中表示时也不会特别大,所以内容可以使用unicode来处理,但是存储和网络传输时一般数据都会非常多,那么增加1倍将是无法容忍的!!!

为了解决存储和网络传输的问题,出现了Unicode Transformation Format,学术名UTF,即:对unicode字符进行转换,以便于在存储和网络传输时可以节省空间!

  • UTF-8: 使用1、2、3、4个字节表示所有字符;优先使用1个字符、无法满足则使增加一个字节,最多4个字节。英文占1个字节、欧洲语系占2个、东亚占3个,其它及特殊字符占4个
  • UTF-16: 使用2、4个字节表示所有字符;优先使用2个字节,否则使用4个字节表示。
  • UTF-32: 使用4个字节表示所有字符;

总结:UTF 是为unicode编码 设计 的一种 在存储 和传输时节省空间的编码方案。

如果你要传输的文本包含大量英文字符,用UTF-8编码就能节省空间:

字符ASCIIUnicodeUTF-8
A0100000100000000 0100000101000001
x01001110 0010110111100100 10111000 10101101

从上面的表格还可以发现,UTF-8编码有一个额外的好处,就是ASCII编码实际上可以被看成是UTF-8编码的一部分,所以,大量只支持ASCII编码的历史遗留软件可以在UTF-8编码下继续工作。

搞清楚了ASCIIUnicodeUTF-8的关系,我们就可以总结一下现在计算机系统通用的字符编码工作方式:

在计算机内存中,统一使用Unicode编码,当需要保存到硬盘或者需要传输的时候,就转换为UTF-8编码。

用记事本编辑的时候,从文件读取的UTF-8字符被转换为Unicode字符到内存里,编辑完成后,保存的时候再把Unicode转换为UTF-8保存到文件。

常用编码介绍一览表

编码制定时间作用所占字节数
ASCII1967年表示英语及西欧语言8bit/1bytes
GB23121980年国家简体中文字符集,兼容ASCII2bytes
Unicode1991年国际标准组织统一标准字符集2bytes
GBK1995年GB2312的扩展字符集,支持繁体字,兼容GB23122bytes
UTF-81992年不定长编码1-3bytes

Py2 Vs Py3编码

python生下来的时候 还没有unicode&utf-8, 所以龟叔选用的默认编码只能是ASCII, 一真到py2.7,用的还是ASCII, 导致Py默认只支持英文,想支持其它语言,必须单独配置。

直接写中文执行会报错的。需在文件开头声明文件的编码才能写中文,再执行就不会有错了。

不过注意如果你的电脑 是windows系统 , 你的系统默认编码是GBK ,你声明的时候要声明成GBK, 不能是utf-8, 否则依然是乱码,因为gbk自然不认识utf-8.

在Py2里编码问题非常头疼,若不是彻底理解编码之间的各种关系,会经常容易出现乱码而不知所措。

到了Py3推出后,终于把默认编码改成了unicode, 同时文件存储编码变成了utf-8,意味着,不用任何声明,你就可以写各种语言文字在你的Python程序里。 从此,程序们手牵手过上了快乐的生活。

秒懂十六进制

16进制,英文名称Hexadecimal(简写Hex), 在数学中是一种逢16进1的进位制。一般用数字0到9和字母A到F(或a~f)表示,其中:A~F表示10~15,这些称作十六进制数字,比如十进制13用16进制表示是D, 28用16进制是1C。

0 1 2 3 4 5 6 7 8 9  A  B  C  D  E  F 
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

16进制在计算机领域应用普遍,常见的有htmlcss的颜色表、mac地址、字符编码等都用16进制来表示。 这是因为将4个位元(Bit)化成单独的16进制数字不太困难。1字节可以表示成2个连续的16进制数字。可是,这种混合表示法容易令人混淆,因此需要一些字首、字尾或下标来显示,在C语言、C++、Shell、Python、Java语言及其他相近的语言使用字首“0x”来标示16进制,例如“0x5A3”代表1443。

16进制转换10进制

为何“0x5A3”代表1443呢? 怎么算出来的?

16进制数转10进制数的原理:1000=1X16^3(16的3次方)+0X16^2(16的2次方)+0X16(16的1次方)+0X1(16的0次方)=4096。

A = 10, B = 11,,C =12,D=13,E=14,F= 15。

FFF=15(16^2) + 15(16^1) + 15*(16^0) = 4095。

10进制转16进制算法

除16取余数得最低1位,然后把商继续除得第2位,直到商等于0

举例:

65036 除 16,余数 12(C),商4064
4064 除 16,余数 0(0),商254
254 除 16,余数 14(E),商15
15除16,余数 15(F),商0,结束
得16进制为 FE0C

最后记住 ,16进制只是一种展示手法,相比2进制展示的更短更易换算,就像我们看10进制一样, 计算机底层运行的肯定还是二进制

原创文章,作者:寒社科长,如若转载,请注明出处:http://www.hanshe123.com/152.html

发表评论

邮箱地址不会被公开。 必填项已用*标注