python自动化运维之路~DAY2
作者:尹正杰
版权声明:原创作品,谢绝转载!否则将追究法律责任。
一.字符编码与转码
1.什么是编码。
基本概念很简单。首先,我们从一段信息即消息说起,消息以人类可以理解、易懂的表示存在。我打算将这种表示称为“明文”(plain text)。对于说英语的人,纸张上打印的或屏幕上显示的英文单词都算作明文。
其次,我们需要能将明文表示的消息转成另外某种表示,我们还需要能将编码文本转回成明文。从明文到编码文本的转换称为“编码”,从编码文本又转回成明文则为“解码”.
2.编码的历史演变。
ASCII编码:
记住一句话:计算机中的所有数据,不论是文字、图片、视频、还是音频文件,本质上最终都是按照类似 01010101 的二进制存储的。再说简单点,计算机只懂二进制数字!所以,目的明确了:如何将我们能识别的符号唯一的与一组二进制数字对应上?于是美利坚的同志想到通过一个电平的高低状态来代指0或1,八个电平做为一组就可以表示出256种不同状态,每种状态就唯一对应一个字符,比如A--->00010001,而英文只有26个字符,算上一些特殊字符和数字,128个状态也够用了;每个电平称为一个比特为,约定8个比特位构成一个字节,这样计算机就可以用127个不同字节来存储英语的文字了。这就是ASCII编码。ASCII编码无法存中文哟!
GB2312编码:
扩展ANSI编码 刚才说了,最开始,一个字节有八位,但是最高位没用上,默认为0;后来为了计算机也可以表示拉丁文,就将最后一位也用上了, 从128到255的字符集对应拉丁文啦。至此,一个字节就用满了! //GB2312 计算机漂洋过海来到中国后,问题来了,计算机不认识中文,当然也没法显示中文;而且一个字节所有状态都被占满了,万恶的帝国主义亡我之心不死啊!我党也是棒,自力更生,自己重写一张表,直接生猛地将扩展的第八位对应拉丁文全部删掉,规定一个小于127的字符的意义与原来相同,但两个大于127的字符连在一起时,就表示一个汉字,前面的一个字节(他称之为高字节)从0xA1用到0xF7,后面一个字节(低字节)从0xA1到0xFE,这样我们就可以组合出大约7000多个简体汉字了;这种汉字方案叫做 “GB2312”。GB2312 是对 ASCII 的中文扩展。
GBK和GB18030编码:
但是汉字太多了,GB2312也不够用,于是规定:只要第一个字节是大于127就固定表示这是一个汉字的开始,不管后面跟的是不是扩展字符集里的内容。结果扩展之后的编码方案被称为 GBK 标准,GBK 包括了 GB2312 的所有内容,同时又增加了近20000个新的汉字(包括繁体字)和符号。
unicode编码:
很多其它国家都搞出自己的编码标准,彼此间却相互不支持。这就带来了很多问题。于是,国际标谁化组织为了统一编码:提出了标准编码准则:UNICODE 。UNICODE是用两个字节来表示为一个字符,它总共可以组合出65535不同的字符,这足以覆盖世界上所有符号(包括甲骨文)
utf-8编码:
unicode都一统天下了,为什么还要有一个utf8的编码呢?unicode存数据不管是中文还是英文,默认都用2个字节来存取!大家想,对于英文世界的人们来讲,一个字节完全够了,比如要存储A,本来00010001就可以了,现在吃上了unicode的大锅饭,得用两个字节:00000000 00010001才行,浪费太严重!基于此,美利坚的科学家们提出了天才的想法:utf8.UTF-8(8-bit Unicode Transformation Format)是一种针对Unicode的可变长度字符编码,它可以使用1~4个字节表示一个符号,根据不同的符号而变化字节长度,当字符在ASCII码的范围时,就用一个字节表示,所以是兼容ASCII编码的。这样显著的好处是,虽然在我们内存中的数据都是unicode,但当数据要保存到磁盘或者用于网络传输时,直接使用unicode就远不如utf8省空间啦!这也是为什么utf8是我们的推荐编码方式。
Unicode与utf8的关系:
一言以蔽之:Unicode是内存编码表示方案(是规范),而UTF8是如何保存和传输Unicode的方案(是实现)这也是UTF8与Unicode的区别。
3.“万国码”
我们在打开一个文件的时候,首先要对文件进行解码,然后才把数据进行打印出来,如果不指定打开的方式就会以系统默认的编码格式进行打开的哟,在python2.7中,系统默认的编码是ASCII,但是在3.0以上就默认使用的是utf-8编码打开。所以在打开文件的时候容易出现冲突,比如你的文件是以gbk格式存储的,但是我打开的方式是以utf-8的方式进行解码打开是会报错的哟!这一点大家要注意了哟!
所有的对象在转码之前都要被解码(decode)然后才能被转码(encode)哟!要注意的是在decode的同时,也会将bytes数据类型转换成str数据类型,在encode的同时,str也会跟着呗转换成bytes类型的哟!
#!/usr/bin/env python
#_*_coding:gbk _*_ (这里仅仅是告诉文件的编码格式,也就是存入磁盘的时候应该保存的编码格式哟~不要和内存的编码【unicode】弄混了哟!)
#__author__ = "yinzhengjie"
import sys
print(sys.getdefaultencoding()) #打印默认编码
name = "尹正杰" #这是定义的一个变量,是内存,所以该变量的编码格式是unicode,所以没有decode方法,因为它本身就是unicode编码的原因!
print( name.encode("gbk")) #由于该变量本身就是unicode就不用decode了,直接encode解码成gbk [它是一个bytes类型,无法显示成汉字]
print( name.encode("utf-8")) #将该变量转码成utf-8
print( name.encode("utf-8").decode("utf-8").encode("gb2312")) #将该变量转换成gb2312,gb2312的编码在gbk中都是一样的,但是后者比前者范围更广哟,由于其实一个bytes类型,如果你想要将其转换成中文,直接解码一下就好使了,因为在encode的同事,这个变量的类型也跟着变了
print( name.encode("utf-8").decode("utf-8").encode("gb2312").decode("gb2312")) #将bytes类型转换成str类型(我们此处可以这么理解,因为在python3中就有这么一个特性,在转码的时候会将类型也跟着变化!)
4.常见的编码问题
1>.cmd下的乱码问题
test.py
文件保存时的编码也会被保存为utf8。
问:什么在IDE下用2或3执行都没问题,在cmd.exe下3正确,2乱码呢?
答:我们在win下的终端即cmd.exe去执行,大家注意,cmd.exe本身也一个软件;当我们python2 hello.py时,python2解释器(默认ASCII编码)去按声明的utf8编码文件,而文件又是utf8保存的,所以没问题;问题出在当我们print'苑昊'时,解释器这边正常执行,也不会报错,只是print的内容会传递给cmd.exe用来显示,而在py2里这个内容就是utf8编码的字节数据,可这个软件默认的编码解码方式是GBK,所以cmd.exe用GBK的解码方式去解码utf8自然会乱码。
py3正确的原因是传递给cmd的是unicode数据,cmd.exe可以识别内容,所以显示没问题。
文件保存时的编码也为utf8。
改成这样后,cmd下用2也不会有问题了。
2>.open()中的编码问题
创建一个hello文本,保存成utf8:
为什么会报错呢?
因为你的win的操作系统安装时是默认的gbk编码,而linux操作系统默认的是utf8编码;
当执行open函数时,调用的是操作系统打开文件,操作系统用默认的gbk编码去解码utf8的文件,自然乱码。
解决办法:
查看效果:
如果你的文件保存的是gbk编码,在win 下就不用指定encoding了。
另外,如果你的win上不需要指定给操作系统encoding='utf8',那就是你安装时就是默认的utf8编码或者已经通过命令修改成了utf8编码。
注意:open这个函数在py2里和py3中是不同的,py3中有了一个encoding=None参数。
5.对比python2与python3的字符编码
先说python2
- py2里默认编码是ascii
- 文件开头那个编码声明是告诉解释这个代码的程序 以什么编码格式 把这段代码读入到内存,因为到了内存里,这段代码其实是以bytes二进制格式存的,不过即使是2进制流,也可以按不同的编码格式转成2进制流,你懂么?
- 如果在文件头声明了#_*_coding:utf-8*_,就可以写中文了, 不声明的话,python在处理这段代码时按ascii,显然会出错, 加了这个声明后,里面的代码就全是utf-8格式了
- 在有#_*_coding:utf-8*_的情况下,你在声明变量如果写成name=u"大保健",那这个字符就是unicode格式,不加这个u,那你声明的字符串就是utf-8格式
- utf-8 to gbk怎么转,utf8先decode成unicode,再encode成gbk
再说python3
- py3里默认文件编码就是utf-8,所以可以直接写中文,也不需要文件头声明编码了,干的漂亮
- 你声明的变量默认是unicode编码,不是utf-8, 因为默认即是unicode了(不像在py2里,你想直接声明成unicode还得在变量前加个u), 此时你想转成gbk的话,直接your_str.encode("gbk")即可以
- 但py3里,你在your_str.encode("gbk")时,感觉好像还加了一个动作,就是就是encode的数据变成了bytes里,我操,这是怎么个情况,因为在py3里,str and bytes做了明确的区分,你可以理解为bytes就是2进制流,你会说,我看到的不是010101这样的2进制呀, 那是因为python为了让你能对数据进行操作而在内存级别又帮你做了一层封装,否则让你直接看到一堆2进制,你能看出哪个字符对应哪段2进制么?什么?自己换算,得了吧,你连超过2位数的数字加减运算都费劲,还还是省省心吧。
- 那你说,在py2里好像也有bytes呀,是的,不过py2里的bytes只是对str做了个别名,没有像py3一样给你显示的多出来一层封装,但其实其内部还是封装了的。 这么讲吧, 无论是2还是三, 从硬盘到内存,数据格式都是 010101二进制到-->b'\xe4\xbd\xa0\xe5\xa5\xbd' bytes类型-->按照指定编码转成你能看懂的文字
编码应用比较多的场景应该是爬虫了,互联网上很多网站用的编码格式很杂,虽然整体趋向都变成utf-8,但现在还是很杂,所以爬网页时就需要你进行各种编码的转换,不过生活正在变美好,期待一个不需要转码的世界。
最后,编码is a piece of fucking shit, noboby likes it.
二.集合的使用
1 #!/usr/bin/env python 2 # _*_coding:utf-8_*_ 3 # __author__:yinzhengjie 4 5 import sys, os 6 7 old_string = sys.argv[1] 8 new_string = sys.argv[2] 9 file = sys.argv[3] 10 11 old_file = open(file, "r", encoding="utf-8") #打开源文件 12 new_file = open("file_bak", "w", encoding="utf-8") #打开一个新的文件 13 for i in old_file: 14 if old_string in i: 15 i = i.replace(old_string, new_string) #字符串的替换功能。 16 new_file.write(i) 17 18 old_file.close() 19 new_file.close() #关闭文件 20 os.rename("file_bak",file)
需要用python3.5环境
1 #!/usr/bin/env python 2 #_*_coding:utf-8_*_ 3 4 import sys,time 5 6 city_info = { 7 "北京":{ 8 "东城区":{ 9 "旅游景点":{ 10 "老舍纪念馆":{ 11 "介绍":"就是我们从小学到大学都要在课文里提到的一个作者哟" 12 }, 13 "故宫":{ 14 "介绍":"我去~我上次的地方是*,我以为*就是故宫呢!" 15 } 16 } 17 }, 18 "西城区":{ 19 "旅游景点":{ 20 "北京海洋馆":{ 21 "简介":"是亚洲第一、世界内陆最大、设施最先进的海洋馆。坐落在北京动物园内,南倚长河、毗邻北京展览馆、天文馆和首都体育馆,交通极为便利。占地12万平方米,建筑面积4.2万平方米,集观赏、科普教育和休闲娱乐为一体,是目前世界最大的内陆水族馆。该馆的总建筑面积达4.2万平方米,绿化面积达8万多平方米。场馆外形采用了别具一格的“海螺”形状,色彩以蓝色和橘红色为基本色调,分别代表了神秘浩瀚的海洋和海洋生物无穷无尽的生命力。其内部设计也别具匠心,屋顶均为网架结构,并采用蓝色和黄色进行装饰,将一个蔚蓝色的世界呈现在人们面前。北京海洋馆以“陶怡大众、教益学生、维系生态”为宗旨。馆内共分六个不同内容的展示场馆、分别命名为雨林奇观、触摸池、海底环游、鲨鱼馆、鲸豚湾和海洋剧院。置身其中,人们不但可以领略不同种类的海洋生物,还可亲身感受人类与海洋的关系。馆内展出各种鱼类达数万尾,其中海洋观赏鱼类及淡水观赏鱼类近千余种。" 22 }, 23 "人民大会堂":{ 24 "简介":"人民大会堂位于北京市中心*广场西侧,西长安街南侧。人民大会堂是中国全国人民代表大会开会的地方,是全国人民代表大会和全国人大常委会的办公场所。是党、国家和各人民团体举行政治活动的重要场所,也是中国国家*和人民群众举行政治、外交、文化活动的场所。" 25 }, 26 "北京动物园":{ 27 "简介":"北京动物园位于北京市西城区西直门外大街,占地面积约86公顷,水面8.6公顷。是中国最大的城市动物园。北京动物园原名农事实验场、天然博物院、万牲园、西郊公园,是中国开放最早、动物种类最多的动物园,从清光绪三十二年(1906年)至今已有逾百年的历史。" 28 }, 29 } 30 }, 31 "丰台区":{ 32 "旅游景点":{ 33 "卢沟桥":{ 34 "简介":"永定河上的卢沟桥,在北京附近,修建于公元1189到1192年间。桥长265米,整座桥由11个半圆形的石拱组成。" 35 }, 36 "北京世界公园":{ 37 "简介":" 集世界名胜于一体的北京世界公园,位于北京丰台区花乡大堡台,总面积46.7公顷,距市中心16公里,距北京西客站8公里,紧邻花乡森林公园。" 38 }, 39 "石景山区":{ 40 "心得":"给我的感觉就是寺庙聚集地区啊,哈哈" 41 }, 42 } 43 }, 44 "朝阳区":{ 45 "旅游景点":{ 46 "北京奥林匹克公园":{ 47 "简介":"北京奥林匹克公园位于北京市朝阳区,地处北京城中轴线北端,北至清河南岸,南至北土城路,东至安立路和北辰东路,西至林翠路和北辰西路,总占地面积11.59平方千米,集中体现了“科技、绿色、人文”三大理念,是融合了办公、商业、酒店、文化、体育、会议、居住多种功能的新型城市区域。" 48 }, 49 "国家体育馆":{ 50 "简介":"建筑面积8.09万平方米,可容纳1.8万人。在奥运期间主要承担竞技体操、蹦床和手球比赛项目。奥运会后,国家体育馆作为北京市一流体育设施,将成为提供多功能服务的市民活动中心。介绍 国家体育馆国位于奥林匹克公园中心区的南部,与“鸟巢”和“水立方”和国家会议中心比邻而居。" 51 }, 52 "朝阳公园":{ 53 "简介":"国家4A级旅游景区。位于北京市朝阳区的中部繁华地段,多条公交线路可达。" 54 }, 55 "国家游泳中心(水立方)":{ 56 "简介":"国家游泳中心又被称为“水立方”,位于北京奥林匹克公园内,是北京为2008年夏季奥运会修建的主游泳馆,也是2008年-标志性建筑物之一。它的设计方案,是经全球设计竞赛产生的“水的立方”方案。其与国家体育场(俗称鸟巢)分列于北京城市中轴线北端的两侧,共同形成相对完整的北京历史文化名城形象。" 57 }, 58 "奥林匹克公园网球场":{ 59 "简介":"位于北京奥林匹克公园内,北邻北五环路,东邻北辰西路,西临白庙村路,南侧为射箭场。总建筑面积26514平方米,总坐席数17400个。2008年-网球比赛将在这里举行。" 60 }, 61 "大望京公园":{ 62 "简介":"大望京公园位于朝阳区崔各庄乡辖区内,北靠北小河,东南临京顺路,东北至五环路,西接望京规划路。总占地面积334000平方米,其中陆地面积310633平方米(绿地面积261608平方米,园路及铺装49025平方米),水面面积23367平方米。大望京是具有悠久历史的区域。大望京比北京的历史还要长几百年。" 63 }, 64 "潘家园旧货市场":{ 65 "简介":"潘家园又有“鬼市”之称。说起“鬼市”还要追溯到清末民初。当时国运衰落,许多达官显贵家道中落,便偷拿了家中的古玩站街变卖。毕竟这是件有-份的事,只能选在凌晨三四点打着灯笼交易。”有多年摆摊经验的霍老不胜唏嘘,“想当年,‘鬼市’上还脱手些来路不明的物件,因为都有着不可言说的秘密,大多只能贱价出售。‘鬼市出好货’的传闻也就传开了。”现在虽然不需要躲躲藏藏、掩人耳目,但是凌晨四点开市的传统被延续了下来。" 66 }, 67 } 68 } 69 }, 70 "陕西":{ 71 "西安市":{ 72 "旅游景点":{ 73 "兵马俑":{ 74 "简介":"现在秦始皇帝陵博物院是通票(包括秦始皇兵马俑博物馆、秦始皇陵、秦始皇陵遗址公园、百戏俑坑博物馆、石铠甲博物馆。遗址公园内有摆渡车,游客可免费乘坐,来往兵马俑和丽园之间)。" 75 }, 76 "华清池":{ 77 "注意":"在临潼吃饭时小心被宰,吃饭前先看好菜单价格。" 78 }, 79 "华山":{ 80 "简介":"乘“亚洲第一索道”游西岳华山 翠华山" 81 }, 82 "碑林博物馆":{ 83 "注意":"可以顺着碑林南围墙一直往西走到书院门步行街(书院门步行街都是书法和一些手工制品,一般看看就行了,不要买。如果实在想买的话,只调一些小玩意买,小心被宰哟)到南门,从南门上明城墙。" 84 } 85 } 86 }, 87 "安康市":{ 88 "旅游景点":{ 89 "南宫山":{ 90 "简介":"南宫山还算不错,我们去的那天观音望海下面全是雾,漂亮极了。走在玻璃栈道上,我一点也没觉得害怕" 91 } 92 } 93 } 94 } 95 96 } 97 98 while True: 99 for i in city_info: 100 print(i) 101 choice = input("\033[32;1mPlease select the area you want to visit, press 'q' or 'Q' to exit the program >>:\033[0m").strip() 102 if choice == "q" or choice == "Q": 103 break 104 elif choice not in city_info: 105 print("\033[31;1m The data you entered is invalid,Please enter the following list of areas\033[0m") 106 continue 107 if choice in city_info: 108 while True: 109 for i2 in city_info[choice]: 110 print("\t",i2) 111 choice2 = input("\033[32;1mPlease choose the autonomous area want to go to,Press :'b' or 'B' to return, press 'q' or 'Q' to exit the program >>:\033[0m").strip() 112 if choice2 == "b": 113 break 114 elif choice2 == "q" or choice2 == "Q": 115 sys.exit() 116 elif choice2 not in city_info[choice]: 117 print("\033[31;1m The data you entered is invalid,Please enter the following list of areas\033[0m") 118 continue 119 if choice2 in city_info[choice]: 120 while True: 121 for i3 in city_info[choice][choice2]: 122 print("\t\t", i3) 123 choice3 = input("\033[32;1mPlease choose the things you are interested in,Press :'b' or 'B' to return, press 'q' or 'Q' to exit the program >>:\033[0m").strip() 124 if choice3 == "b": 125 break 126 elif choice3 == "q" or choice3 == "Q": 127 sys.exit() 128 elif choice3 not in city_info[choice][choice2]: 129 print( 130 "\033[31;1m The data you entered is invalid,Please enter the following list of areas\033[0m") 131 continue 132 if choice3 in city_info[choice][choice2]: 133 while True: 134 for i4 in city_info[choice][choice2][choice3]: 135 print(i4) 136 choice4 = input("\033[32;1mPlease choose the scenic spots you want to visit,Press :'b' or 'B' to return, press 'q' or 'Q' to exit the program >>:\033[0m").strip() 137 if choice4 == "b": 138 break 139 elif choice4 == "q" or choice4 == "Q": 140 sys.exit() 141 elif choice4 not in city_info[choice][choice2][choice3]: 142 print( 143 "\033[31;1m The data you entered is invalid,Please enter the following list of areas\033[0m") 144 continue 145 if choice4 in city_info[choice][choice2][choice3]: 146 while True: 147 for i5 in city_info[choice][choice2][choice3][choice4]: 148 print(i5) 149 choice5 = input("\033[32;1mPlease select the information to change the line,Press :'b' or 'B' to return, press 'q' or 'Q' to exit the program >>:\033[0m").strip() 150 if choice5 == "b": 151 break 152 elif choice5 == "q" or choice5 == "Q": 153 sys.exit() 154 elif choice5 not in city_info[choice][choice2][choice3][choice4]: 155 print( 156 " \033[31;1m The data you entered is invalid,Please enter the following list of areas\033[0m") 157 continue 158 if choice5 in city_info[choice][choice2][choice3][choice4]: 159 print(city_info[choice][choice2][choice3][choice4][choice5]) 160 for i in range(5): 161 print("\033[35;1m已经是字典的底层了哟~请安Q或者B进行操作,%s秒后返回上级清单\033[0m" % (5-i)) 162 time.sleep(1)
代码如下:
1 #!/usr/bin/env python 2 #coding:utf-8 3 #__author__:yinzhengjie 4 import time,sys 5 sale_list = [ 6 ('watch',3188), 7 ('ipad mini',4588), 8 ('macbook air',6988), 9 ("摩托车",3290), 10 ("电动自行车",3199), 11 ("锂电池自行车",2488), 12 ("自行车",340), 13 ("咖啡",85), 14 ("奶茶",56), 15 ("彩电",3199), 16 ("冰箱",6599), 17 ("洗衣机",3499), 18 ("男士羽绒服",799) 19 ] 20 shopping_list = [] 21 total_consumption = 0 22 customer_deposit = input("请问您有多少存款>>: ") 23 if customer_deposit.isdigit(): 24 customer_deposit = int(customer_deposit) 25 print() 26 while True: 27 for index, item in enumerate(sale_list): 28 print(index, item) 29 user_choice = input("请选择相应的序列号来挑选商品>>: ") 30 if user_choice.isdigit(): 31 user_choice = int(user_choice) 32 if user_choice < len(sale_list) and user_choice >= 0: 33 purchase_items = sale_list[user_choice] 34 if purchase_items[1] <= customer_deposit: 35 shopping_list.append(purchase_items) 36 customer_deposit -= purchase_items[1] 37 total_consumption += purchase_items[1] 38 print(purchase_items[1]) 39 print(total_consumption) 40 print("已经订单的商品:'%s'" % purchase_items[0] ) 41 print("") 42 continue_shopping = input("请问是否要继续购物呢(按任意键继续,按'Q'或者'q'停止购物)>>: ") 43 if continue_shopping == "q": 44 for i in shopping_list: 45 print("您已经订单的商品‘%s’,需要花费‘%s’元人名币" % (i[0],i[1])) 46 print("您的存款是\033[31;1m%s\033[0m" % (customer_deposit + purchase_items[1])) 47 print("共需要消费\033[31;1m%s\033[0m人民币" % total_consumption) 48 spend=input("是否确认购买物品(按任意键退出退出程序,按'y'确认结账)") 49 if spend == "y": 50 51 print("欢迎来到尹正杰商城进行消费!当前您的余额是:\033[31;1m'%s'\033[0m" %customer_deposit) 52 sys.exit() 53 else: 54 print("退出商城") 55 sys.exit() 56 57 else: 58 print("\033[41;1m您的余额只剩【%s】啦,还买个毛线啊\033[0m" % customer_deposit) 59 else: 60 print(" 对不起您输入的序列号不正确!请重新输入!!! ") 61 print("") 62 time.sleep(2) 63 continue