一、json
序列化
把对象(变量)从内存中变成可存储或传输的过程
反序列化
把变量内容从序列化的对象重新读到内存里
可以通过eval对数据进行序列化
dic=‘{"name":"alex"}‘
f=open("hello","w")
f.write(dic)
f_read=open("hello","r")
data=f_read.read()#是个字符串
print(type(data))
data=eval(data) #很多语言都支持,但是有局限性,但是函数、类它存不了
print(data["name"])
json
什么是json
如果我们要在不同的编程语言之间传递对象,就必须把对象序列化为标准格式,比如XML,但更好的方法是序列化为JSON,因为JSON表示出来就是一个字 符串,可以被所有语言读取,也可以方便地存储到磁盘或者通过网络传输。JSON不仅是标准格式,并且比XML更快,而且可以直接在Web页面中读取,非 常方便。
注意1:json不能序列化类,不过序列化函数和类没有意义,除非你传过去的那边也有个相同的函数
###通过json对数据进行序列化###
import json
dic = {’name’:"alex"}
f = open("test","w")
data = json.dumps(dic)
f.write(data) ##json.dump(dic,f)把dumps和f.write()合起来,仅限文件操作,所以不推荐用
f.close()
json序列化处理的内容:把字符串的的单引号变成双引,并把数据(数字、列表、字典、元组等)变成字符串。上述data就变成了字符串,其他语言能用
# dic={‘name‘:‘alex‘} #---->{"name":"alex"}----->‘{"name":"alex"}‘
# i=8 #---->‘8‘
# s=‘hello‘ #---->"hello"------>‘"hello"‘
# l=[11,22] #---->"[11,22]"
############################
###通过json对数据进行反序列化###
import json
f = open("test","r")
data = json.loads(f.read()) # data=json.load(f)把open和loads两部合起来
print(data)
print(type(data))
f.close()
这个例子也说明了,不一定要有dumps才能loads出来。只要它符合json规范,就可以被解释、被loads
#############################
二、pickle
跟json的作用一样,但是它只能用于Python内部的数据交换,不能跨语言,也只有dumps(dumps)和loads(load)两个方法
###通过pickle对数据进行序列化###
import pickle
dic = {‘name‘: ‘alvin‘, ‘age‘: 23, ‘sex‘: ‘male‘}
f = open("ptest","wb")
data = pickle.dumps(dic) #会变成字节类型,所以要用wb模式
print(type(data))
f.write(data)
f.close()
##############################
###通过pickle对数据进行反序列化###
import pickle
f = open("ptest","rb")
data = pickle.loads(f.read()) #会变成字节类型,所以要用wb模式
print(data["name"])
print(type(data))
f.close()
三、XML
实现不同语言或程序之间进行数据交换的协议,作用跟json类似,但是比json复杂。所有的数据都通过标签的实现,文档树结构。Java必学,金融领域不可 缺少。
XML文件结构,如下面的例子:
<data>
<country name="Liechtenstein">
<rank updated="yes">2</rank>
<year updated="yes">2010</year>
<gdppc>141100</gdppc>
<neighbor direction="E" name="Austria" />
<neighbor direction="W" name="Switzerland" />
</country>
<country name="Singapore">
<rank updated="yes">5</rank>
<year updated="yes">2013</year>
<gdppc>59900</gdppc>
<neighbor direction="N" name="Malaysia" />
</country>
<country name="Panama">
<rank updated="yes">69</rank>
<year updated="yes">2013</year>
<gdppc>13600</gdppc>
<neighbor direction="W" name="Costa Rica" />
<neighbor direction="E" name="Colombia" />
</country>
</data>
###xml模块###
import xml.etree.ElementTree as ET
tree = ET.parse("xml_lesson") #拿到整个树结构
root = tree.getroot() #拿到根节点
print(root.tag)#打印根节点的标签data
###遍历XML###
import xml.etree.ElementTree as ET
tree = ET.parse("xml_lesson") #拿到整个树结构
root = tree.getroot() #拿到根节点
for child in root: #拿到根节点下的次节点
print(child.tag, child.attrib) #次节点的标签和属性
for i in child: #拿到次节点下的子节点
print(i.tag, i.text) #子节点的标签和文本内容
###只遍历year节点###
for node in root.iter(‘year‘): #如果你在country里拿,那就只能取到一个,所以要在根节点用iter方法
print(node.tag, node.text)
###修改###
for node in root.iter(‘year‘):
new_year = int(node.text) + 1 #修改年份
node.text = str(new_year) #必须转换成字符串
node.set("updated", "yes") #新增一个属性
tree.write("xml_lesson") #文件名不一样就另存为一个文件
###删除节点###
for country in root.findall(‘country‘): #这样就不用再用for循环遍历下一个country,findall是找多个
rank = int(country.find(‘rank‘).text)
if rank > 50:
root.remove(country)
tree.write(‘output.xml‘)
###生成一个XML###
import xml.etree.ElementTree as ET
new_xml = ET.Element("namelist") #创建一个根节点,即<namelist>...</namelist>
name = ET.SubElement(new_xml, "name", attrib={"enrolled": "yes"})#插入name标签,添加一个属性
age = ET.SubElement(name, "age", attrib={"checked": "no"})
sex = ET.SubElement(name, "sex")
sex.text = ‘33‘
name2 = ET.SubElement(new_xml, "name", attrib={"enrolled": "no"})
age = ET.SubElement(name2, "age")
age.text = ‘19‘
et = ET.ElementTree(new_xml) # 生成文档对象
et.write("test.xml", encoding="utf-8", xml_declaration=True)
ET.dump(new_xml) # 打印生成的格式
四、re模块
正则表达式(或 RE)是一种小型的、高度专业化的编程语言,它内嵌在Python中,并通过re模块实现。正则表达式模式被编译成一系列的字节码,然后由用 C 编写的匹配 引擎执行
正则主要是用于解决模糊匹配,一个现实生活的例子:从身份证号码找出“1970出生的广东省人”
372324199206034957 男 山东省***
623021198705154958 男 甘肃省***
429004194306184959 男 湖北省
530111197101224956 男 云南省昆明市***
440582199706174955 男 广东省***
210711198901144954 男 辽宁省锦州市***
450521198612214953 男 广西***
321119195110314952 男 江苏省***
字符匹配(普通字符和元字符)
1.普通字符:大多数字符和字母都会和自身匹配
>>> re.findall("ljy","dsafjaljydfjeiw")
[‘ljy‘]
2.元字符:. ^ $ * + ? { } [ ] | ( ) \
元字符之. ^ $ * + ? { }
>>> a = re.findall("l..y","dfjljuyaiq") #点是通配符,每一个点代表一个字符,除了\n以外的字符都能匹配
>>> print(a)
[‘ljuy‘]
>>> b = re.findall("^l..y","dfjljuyailabyq") # ^表示以字符串什么为开头,必须是整个字符串的开头才能匹配出来,就是说l一定要出现在字符串的第一位
>>> print(b)
[]
>>> b = re.findall("^l..y","ljuyailabyq")
>>> print(b)
[‘ljuy‘]
>>> ret = re.findall("a...j$","dsfkjsdakfyj") # $表示字符串以什么结尾,所以,j一定要出现在字符串的最后一位
>>> print(ret)
[‘akfyj‘]
>>> ret = re.findall("a...j$","dsfkjsdakfyj$")
>>> print(ret)
[]
>>> ret = re.findall("abc*","dsfkjabccccsdafyj") # *表示[0,+oo]
(贪婪匹配),abc*匹配规则中,c字符可以出现0次或者1次或者无限次,但是它只给你返回最高次数
>>> print(ret)
[‘abcccc‘]
>>> ret = re.findall("abc+","dsfkjabccccsdafyj") # +表示[1,+oo]
(贪婪匹配),abc*匹配规则中,c字符可以出现1次或者2次或者无限次,但是它只给你返回最高次数
>>> print(ret)
[‘abcccc‘]
>>> ret = re.findall("abc+","dsfkjabsdafyj") #但是c字符不能出现0次
>>> print(ret)
[]
>>> ret = re.findall("abc?","dsfkjabccccsdafyj") # ? 表示[0,1]
(贪婪匹配),abc*匹配规则中,c字符可以出现0次或者1次,但是它只给你返回最高次数
>>> print(ret)
[‘abc‘]
>>> ret = re.findall("abc{1,3}","dsfkjabccccsdafyj") # {n,m}表示前面的字符出现n次到m次
(贪婪匹配),abc{1,3}匹配规则中,c字符可以出现1次到3次,但是它只给你返 回最高次数
>>> print(ret)
[‘abccc‘]
>>> ret = re.findall("abc{2}","dsfkjabccccsdafyj")
>>> print(ret)
[‘abcc‘]
注意:前面的*,+,?,{}等都是贪婪匹配,也就是尽可能匹配,后面加?号使其变成惰性匹配
>>> ret = re.findall("abc*?","dsfkjabccccsdafyj")
>>> print(ret)
[‘ab‘]
元字符之字符集[ ]:
>>> ret = re.findall("a[bc]d","dsfkjacdsdafyj") #[bc]表示匹配到b或者c或者bc
>>> print(ret)
[‘acd‘]
>>> ret = re.findall("[a-z]","dsfkjacdsdafyj") #匹配所有小写字母
>>> print(ret)
[‘d‘, ‘s‘, ‘f‘, ‘k‘, ‘j‘, ‘a‘, ‘c‘, ‘d‘, ‘s‘, ‘d‘, ‘a‘, ‘f‘, ‘y‘, ‘j‘]
>>> ret = re.findall("[.*+]","a.*+") # . * +这三个元字符放到[]括号里面就失去功能,只是普通的字符
>>> print(ret)
[‘.‘, ‘*‘, ‘+‘]
在字符集里面有功能的符号:\ ^ -
>>> ret = re.findall("[0-9]","45bdha8") #匹配0到9之间的数字
>>> print(ret)
[‘4‘, ‘5‘, ‘8‘]
>>> ret = re.findall("\d","45bdha8") # 匹配十进制数字
>>> print(ret)
[‘4‘, ‘5‘, ‘8‘]
>>> ret = re.findall("[^a]","45bdha8") #[^a]表示取反,不匹配a
>>> print(ret)
[‘4‘, ‘5‘, ‘b‘, ‘d‘, ‘h‘, ‘8‘]
>>> ret = re.findall("[^abcde]","4e5bddhca8") # 不匹配a、b、c、d、e这五个字符
>>> print(ret)
[‘4‘, ‘5‘, ‘h‘, ‘8‘]
元字符之转义符\
反斜杠后面跟元字符:去除特殊功能,如\.
反斜杠后面跟普通字符:实现特殊功能
\d 匹配任何十进制数;它相当于类 [0-9]。
\D 匹配任何非数字字符;它相当于类 [^0-9]。
s 匹配任何空白字符;它相当于类 [ \t\n\r\f\v]。
\S 匹配任何非空白字符;它相当于类 [^ \t\n\r\f\v]。
\w 匹配任何字母数字字符;它相当于类 [a-zA-Z0-9_]。
\W 匹配任何非字母数字字符;它相当于类 [^a-zA-Z0-9_]
\b 匹配一个特殊字符边界,比如空格 ,&,#等
>>> ret = re.findall("I\b","I AM NOONE")
>>> print(ret)
[]
>>> ret = re.findall("I\\b","I AM NOONE")
>>> print(ret)
[‘I‘]
>>> ret = re.findall(r"I\b","I AM NOONE")
>>> print(ret)
[‘I‘]
疑惑:\b在正则中本来就有特殊意义,为何还要加r或者再加一个\?
因为上面的语句是在python解释器执行的。在re中,它用自己的语言,用\b是可以直接匹配出来的。但现在的执行过程是:Python解释器
先执行一遍,即读到\b时,python解释器会把它翻译成对应的内容。当python把翻译后的内容交给re时,已经不是re认识的\b。
r就是raw,规则前面加上r就是告诉python解释器不要进行任何翻译,把\b以生肉的形式交给re。
至于在\b前面加\的原因,是为了取消后面的\的特殊意义,让它变成一个普通的\,python就不会对它进行翻译,所以普通的\和b就传进去给re,而re认识\b,所以能匹配 成功。
>>> re.findall("c\\l","abc\lerwt")
[]
>>> re.findall("c\\\\l","abc\lerwt")
[‘c\\l‘]
re层:为了匹配"c\l",用的是"c\\l",把\转义一下,也就是需要python解释器把"c\\l"传进来
python解释器层:为了把"c\\l"传给re,python需要对每个斜杠进行转义,所以就是"c\\\\l"
为什么返回的是"c\\l",因为python的"c\\\\l"传进re就成了"c\\l",而re里面"c\\l"的结果就是"c\l",所以匹配到就返回"c\\l"给python
python------->re------->"对象"
"c\\\\l" "c\\l" "c\l"
python<-------re<-------"对象"
元字符之分组()
>>> re.findall("(ab)","abdafb")
[‘ab‘]
>>> re.findall("(ab)+","abdabfb")
[‘ab‘, ‘ab‘]
以标签名分组
>>> res = re.search(‘(?P<id>\d{2})/(?P<name>\w{3})‘,‘23/com‘)
>>> print(res)
<_sre.SRE_Match object at 0x7f79a06b4030>
>>> res.group()
‘23/com‘
>>> res.group(‘id‘)
‘23‘
>>> res.group(‘name‘)
‘com‘
元字符之|
>>> res = re.findall(‘(rab)|8‘,‘rabhdg8sd‘)
>>> print(res)
[‘rab‘, ‘‘]
>>> res = re.search(‘(rab)|8‘,‘rabhdg8sd‘)
>>> res.group()
‘rab‘
#()好像就是惰性匹配,匹配到一个就返回,不再进行匹配
3.re模块的常用方法
>>> re.findall(‘a‘,"alvin yuan")
[‘a‘, ‘a‘] #返回所有满足匹配条件的结果,放在列表里
>>> re.search(‘a‘,"alvin yuan").group()
‘a‘ #只会找第一个,最短寻找,re.search().group()打印匹配结果,在写计算器的时候很有用
>>> re.match(‘a‘,"lavin yuan")
>>> re.match(‘a‘,"alvin yuan")
<_sre.SRE_Match object at 0x7f79a6dc1f38>
>>> re.match(‘a‘,"alvin yuan").group() #
‘a‘ #当于在search的基础上加了一个^,就是第一个字符必须匹配上
re.split()以什么进行分割 re.split("[ab]","asdabcd")
>>> re.split("[ab]","asdabcd")
[‘‘, ‘sd‘, ‘‘, ‘cd‘]
过程分析
先按a分割,左边是空,右边是sdabcd,得到["",sdabcd]
因为还有a所以再按a分割,得到["","sd","bcd"]
没有a就按b分割bcd,左边是空,右边是cd,得到["","sd","","cd"]
re.sub("匹配规则","new","old")
>>> ret = re.sub("\d","abc","alvin5yuan6")
>>> print(ret)
alvinabcyuanabc
>>> ret = re.sub("\d","abc","alvin5yuan6",1) #最后一位限制替换的个数
>>> print(ret)
alvinabcyuan6
re.subn("匹配规则","new","old")返回一个元组,包括了替换后的结果和替换的次数
>>> ret = re.subn("\d","abc","alvin5yuan6")
>>> print(ret)
(‘alvinabcyuanabc‘, 2)
>>> rul = re.compile("\d+") #将写好的规则赋给一个变量
>>> rul.findall("324dafkjadsnf324jff")
[‘324‘, ‘324‘]
与re.findall("\d+","324dafkjadsnf324jff")没有区别,除非在多次调用时,后者需要多次编译,但是
前者不用。
a = re.finditer(‘\d‘,‘ds3sy4784a‘)迭代匹配,数据很大的时候用。next(a).group()取出结果
>>> a = re.finditer("\d","ds3sy4784a")
>>> print(a)
>>> next(a).group()
‘4‘
>>> next(a).group()
‘7‘
>>> next(a).group()
‘8‘
>>> next(a).group()
‘4‘
>>> next(a).group()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
findall需要注意的一点:
>>> res = re.findall("www.(baidu|163).com","www.baidu.com")
>>> print(res)
[‘baidu‘]
我们期望的结果的是“www.baidu.com”,但是findall跟组“()”结合的话,会优先把组里面的匹配结果返回,可以通过取消权限去避免
>>> res = re.findall("www.(?:baidu|163).com","www.baidu.com")
>>> print(res)
[‘www.baidu.com‘]