今天我们来讲一讲正则表达式与json,这些知识将涉及到WEB开发和爬虫开发等等一系列项目。
我在学习的过程中,发现一个不错的网站,也是一个比较知名的网站,就是菜鸟教程:http://www.runoob.com
这个网站的知识点汇总还是很齐全的。
正则表达式是一个特殊的字符序列,它能帮助你方便的检查一个字符串是否与某种模式匹配。能快速检索文本,实现一些替换文本的操作。
使用的时候,需要引用re模块,re 模块使 Python 语言拥有全部的正则表达式功能。
一.re.findall
re.findall功能:在字符串中找到正则表达式所匹配的所有子串,并返回一个列表,如果没有找到匹配的,则返回空列表。
例子如下:
import re
a='one3# 6\\two@8\t_three\n^go'
b=re.findall('two',a) #匹配指定的字符串,输出结果是['two']
c=re.findall('\d',a) #匹配任意的数字,输出结果是['3', '6', '8']
d=re.findall('\D',a) #匹配任意非数字,包括空白,输出结果是['o', 'n', 'e', '#', ' ', '\\', 't', 'w', 'o', '@', '\t', '_', 't', 'h', 'r', 'e', 'e', '\n', '^', 'g', 'o']
e=re.findall('\w',a) #匹配数字和字母以及下划线,输出结果是['o', 'n', 'e', '3', '6', 't', 'w', 'o', '8', '_', 't', 'h', 'r', 'e', 'e', 'g', 'o']
f=re.findall('\W',a) #匹配非(字母数字下划线),包括空白,输出结果是['#', ' ', '\\', '@', '\t', '\n', '^']
g=re,findall('\s',a) #匹配空白符号,包括相关制表符,输出结果是[' ', '\t', '\n']
h=re.findall('\S',a) #匹配非(空白符号,相关制表符),输出结果是['o', 'n', 'e', '3', '#', '6', '\\', 't', 'w', 'o', '@', '8', '_', 't', 'h', 'r', 'e', 'e', '^', 'g', 'o']
print(b)
print(c)
print(d)
print(e)
print(f)
print(g)
print(h)
输出结果:
['two']
['3', '6', '8']
['o', 'n', 'e', '#', ' ', '\\', 't', 'w', 'o', '@', '\t', '_', 't', 'h', 'r', 'e', 'e', '\n', '^', 'g', 'o']
['o', 'n', 'e', '3', '6', 't', 'w', 'o', '8', '_', 't', 'h', 'r', 'e', 'e', 'g', 'o']
['#', ' ', '\\', '@', '\t', '\n', '^']
[' ', '\t', '\n']
['o', 'n', 'e', '3', '#', '6', '\\', 't', 'w', 'o', '@', '8', '_', 't', 'h', 'r', 'e', 'e', '^', 'g', 'o']
我们在这段程序中介绍了常见的其中匹配模式,我们可以总结出规律,同种字母的大小写,匹配的模式对立的;大小写对应的匹配模式如果并集,是等同于一个完整的原字符串。
那么。下面将会介绍更多的常见匹配模式:
import re
a='6A5e*8W-y09ud\pOc7wD'
b=re.findall('[a-z]',a) #匹配a到z的小写字母,输出结果是:['e', 'y', 'u', 'd', 'p', 'c', 'w']
c=re.findall('[A-Z]',a) #匹配A到Z的大写字母,输出结果是:['A', 'W', 'O', 'D']
d=re.findall('[0-9]',a) #匹配0到9的所有数字,输出结果是:['6', '5', '8', '0', '9', '7']
e=re.findall('[A-Za-z0-9]',a) #匹配所有数字和大小写字母,输出结果是:['6', 'A', '5', 'e', '8', 'W', 'y', '0', '9', 'u', 'd', 'p', 'O', 'c', '7', 'w', 'D']
f=re.findall('[^abcde]',a) #匹配除了abcde小写字母以外所有的字符,输出结果是:['6', 'A', '5', '*', '8', 'W', '-', 'y', '0', '9', 'u', '$', 'p', 'O', '7', 'w', 'D']
g=re.findall('[^A-Z]',a) #匹配除了A到Z所有大写字母以外的所有字符,输出结果是:['6', '5', 'e', '*', '8', '-', 'y', '0', '9', 'u', 'd', '$', 'p', 'c', '7', 'w']
print(b)
print(c)
print(d)
print(e)
print(f)
print(g)
输出结果:
['e', 'y', 'u', 'd', 'p', 'c', 'w']
['A', 'W', 'O', 'D']
['6', '5', '8', '0', '9', '7']
['6', 'A', '5', 'e', '8', 'W', 'y', '0', '9', 'u', 'd', 'p', 'O', 'c', '7', 'w', 'D']
['6', 'A', '5', '*', '8', 'W', '-', 'y', '0', '9', 'u', '$', 'p', 'O', '7', 'w', 'D']
['6', '5', 'e', '*', '8', '-', 'y', '0', '9', 'u', 'd', '$', 'p', 'c', '7', 'w']
那么这些就是更多常见的匹配模式,千万要避免这些错误的写法: ’^abcde‘ , '^[A-Z]' 等等。
接下来,我将拓展更多的匹配模式……
面对一个乱七八糟的字符串,你想从中提取有效的信息,比如指定长度:
import re
a=‘sett3oi23oisyudga2isydhjb2siygk%sos2*sjjbdjb'
#可能这段字符看起来非常糟糕,但可以尝试索取一下你认为最可能的信息
b=re.findall('[a-z]{1,3}',a) #匹配a到z字母中的长度在1到3之间的字符串
print(b)
输出结果是:
['set', 't', 'oi', 'ois', 'yud', 'ga', 'isy', 'dhj', 'b', 'siy', 'gk', 'sos', 'sjj', 'bdj', 'b'] #里面有一个sos求救信号。
细心的你发现了吗,你发现了一个sos的字符串,这个很明显是你要提取的求救信息。
当然,有些初心的入学者,会不注意大小写的匹配情况:
import re
a=’Java、C#|C++#PYThon‘
b=re.findall('python',a)
print(b)
去尝试运行,却发现报错,报错内容竟是找不到匹配的相应字符串。
是因为大小写并不一样,原字符串中是’PYThon‘,前面三个字母是大写的,自然是匹配不出来的。
所以后面需要加一个修饰符re.I,使匹配对大小写不敏感:
import re
a='Java、C#|C++#PYThon'
b=re.findall('python',a,re.I)
print(b)
输出结果:
['PYThon'] #不要陷入误区,输出结果并不会是['python'],输出结果是字符串里面匹配出来的。
我们会经常碰到重复字符串,我们同样也需要提取处理,比如‘fuc09fuckk7efuck28s’,但是我们可以发现,如果直接进行对‘fuck’提取处理,会提取出好几个类似的‘fuc’,‘fuckk’等,这样会很耗时。
这就涉及到贪婪匹配和非贪婪匹配模式的知识点:
* 将有关的字符全部打印出来,包括正确,少打,多打的情况。
+ 将有关的字符打印出来,只包括正确,多打的情况。
? 将有关的字符打印出来,包括少打,正确的情况,对多打的情况匹配正确的情况。
首先先确定目标字符串‘fuck’,然后选择一种匹配模式,加在字符串后面,最后进行匹配处理。
我们来应用到代码之中:
import re
a='fuc09fuckk7efuck28s'
b=re.findall('fuck*',a) #提取正确,少打,多打的字符串,输出结果是:['fuc', 'fuckk', 'fuck']
c=re.findall('fuck+',a) #提取正确,多打的字符串,输出结果是:['fuckk', 'fuck']
d=re.findall('fuck?',a) #提取正确,少打的字符串,对多打的字符串提取正确的字符串。输出结果是:['fuc', 'fuck', 'fuck']
print(b)
print(c)
print(d)
输出结果:
['fuc', 'fuckk', 'fuck']
['fuckk', 'fuck']
['fuc', 'fuck', 'fuck']
二.re.sub
re.sub用于替换字符串中的匹配项,是对字符串的指定部分进行正则替换操作的函数。公式如下:
re.sub(pattern, repl, string, count=0, flags=0)
pattern是字符串中要更换的部分,repl是更换的内容,string是原始字符串。
count是需要更换的次数,按顺序更换。其中,count=0是默认替换全部,而不是替换0个。
flags是可选的,表示匹配模式,比如忽略大小写,多行模式等
来看看一段简单的替换,助于理解:
a='fuckGOyouRISHME'
b=re.sub('GO','COME',a)
print(b)
输出结果:
fuckCOMEyouRISHME
很显然,其中的GO替换成COME了。当然了,千万不要犯错误,比如输入‘go’替换,这样会报错大小写不匹配噢。
解决的方法当然是使这个过程不对大小写敏感,后面加一个修饰符re.I就行:b=re.sub('go','COME',a,re.I)
等等,难道你们没有发现我这段代码不对劲吗,还有我写的东西也不对劲吗?
没发现,直接运行,会直接报错吗?很显然,我上面这段话,犯了两个错误:
①编写代码的时候,永远都不要忘了你要引用re功能的时候,开头加一句import re,否则就不能使用re.sub的功能。
②读文章的时候,记得要养成动手的习惯,也要记住我说过的东西。
我在上面就写了re.sub的公式:re.sub(pattern, repl, string, count=0, flags=0),请问我按照公式严格写了吗?
所以b=re.sub(‘go’,'COME',a,re.I)是错误的写法,因为python会把re.I误识别为count的部分,而并非是flags部分。
正确的写法是:b=re.sub(‘go’,'COME',a,0,re.I)
不要相信我上面写的输出结果是多少,这个世界上只有你亲自打印出来的输出结果是正确的。
永远保持动手能力和一颗质疑的心,亲自敲出来的代码才是正确的代码。
所以,纠正一下上面的一大段话,正确的代码如下:
import re
a='fuckGOyouRISHME'
b=re.sub('GO','COME',a)
c=re.sub('go','COME',a,0,re.I) #匹配不受大小写影响。
print(b)
print(c)
输出结果:
fuckCOMEyouRISHME
fuckCOMEyouRISHME
注意,re.sub一定要严格按照公式编写,如果要用到后面修饰符的功能,count部分需要写个0。
接下来我们看看这个公式中count部分的应用吧!
import re
a='fuckGOyouGORISHGOME'
b=re.sub('GO','66',a,0)
c=re.sub('GO','66',a,2)
print(b)
print(c)
输出结果:
fuck66you66RISH66ME #count=0是指默认全部替换,而不是替换0个。
fuck66you66RISHGOME #count=2,按顺序替换前面两个GO 。
来看看对这一段程序执行的功能的白话解释:当字符串中想要更换的部分存在多个,可以后面再添加一个参数,控制更换的数量,按顺序。
输出结果中,count=0很显然并不是一般意义上的0个,而是默认全部替换。当count=2时,会按顺序替换前面两个。
当然了,re.sub的花样并不是只有这么多,还可以进行一个删除的操作,那就是将替换的部分替换成无,不就是变相删除吗?
import re
a='fuckGOyouGORISHGOME'
b=re.sub('GO',' ',a)
print(b)
输出结果:
fuckyouRISHME
当然了,玩花活是可以的,可以将这一段函数复杂化:
import re
a='fuckGOyouGORISHGOME'
def convert1(value):
pass
b=re.sub('GO',convert1,a)
print(b)
输出结果:
fuckyouRISHME
所以可以看到,公式里的repl部分是可以用函数操作的。
这段函数的意思就是,在re.sub的替换操作之下,对GO进行convert1函数的pass操作,也就是换成无,也就是删除。
所以,这一段的作用就是去掉所有GO。
当然了,除了替换无之外,还能替换添加字符的操作,比如将GO替换成666GO666,传统方法可以直接做到,但在此介绍用函数的方法替换:
import re
a='fuckGOyouGORISHGOME'
def convert2(value):
matched=value.group() #将同时匹配到的三个’GO‘字符进行分组有序化,防止python不知道先处理哪一个而出错。
return '666'+ matched +'666'
b=re.sub('GO',convert2,a)
c=re.sub('GO',convert2,a,2)
print(b)
print(c)
输出结果:
fuck666GO666you666GO666RISH666GO666ME
fuck666GO666you666GO666RISHGOME
这段函数的意思就是,在re.sub的替换操作之下,将GO替换成666GO666。
那么,为什么要对value进行group()操作呢,不能直接return吗?value本身不就是字符串吗?
原因啊,其实很简单,在匹配GO字符串出来的时候,其实是有三个GO被同时匹配出来,直接替换会被报错,python不知道怎么按顺序。
所以,建立一个matched变量,将value变量里面匹配出来的三个GO进行分组操作,让它有序。
注意,return的时候,要用str数据类型去返回,这样就是字符串替换字符串的正确过程。
c变量的作用很好猜,自然是只替换前两次的GO。
当然了,re,sub还能和if条件语句一起完成替换的过程:
import re
a='AKH8787AS67F67SF6A89'
def convert3(value):
matched=value.group()
if int(matched) > 7: #注意,匹配出来的数字是str数据类型。
return '0'
else:
return '1'
b=re.sub('\d',convert3,a) #将\d匹配出来的数字进行函数convert3的处理。
print(b)
输出结果:
AKH0101AS11F11SF1A00
这一段就是一个数字替换的函数,首先\d匹配出所有的数字,然后按照函数内容来更换,得到最后的结果。
注意,这次我犯了个错误,return后面的0和1我都没有打上srt引号,导致报错。
要知道,value匹配'\d'的结果是str类型的数字,然后经过group()分组处理得出的matched变量还是str类型。
所以更换数字要同样的str类型去return。
以上就是re.sub的一些常见替换用法。
三.re.matched和re.search
re.match 尝试从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话,match()就返回none。
re.search 扫描整个字符串并返回第一个成功的匹配
a='life is short,i use python.'
b=re.search('life.*python',k)
print(b)
print(b.group())
首先,打印出输出结果
<re.Match object; span=(0, 26), match='life is short,i use python'>
life is short,i use python
我们可以看到,第一条打印的是程序运行的过程,并不是用户想要看到的最终输出。
于是第二条进行分组化,将匹配出来的字符串包装,进行打印。
life. 是以life开头往后匹配;*python,是pytho前所有的都匹配出来。两者都包含本身。
那么两者有什么不同之处呢?
re.match只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回None;而re.search匹配整个字符串,直到找到一个匹配。
那么以上这些就是python中的正则表达式,那么如何赋予应用呢,我们来看看JSON吧。
什么是JSON?
英文全名:JavaScript Object Notation
中文翻译: Javascript对象标记
JSON是一种轻量级的数据交换格式,易于人阅读和编写,网络传输效率高。
记住,JSON是一种数据形式,JSON的表现形式是字符串。
凡符合JSON格式的字符串就叫做JSON字符串。
JSON的作用很强大,可以完成跨语言交换数据的功能。
比如现有不同的A语言和B语言,若想要进行转换,中间的桥自然就是JSON数据形式。
那么如果要使用JSON函数,还是一如既往的引用库:import json
那么这方面我们只需要了解两个函数:
①json.loads
作用:用于解码JSON数据,返回Python数据类型。
{'name': '666', 'age': '18'}
<class 'dict'>
<class 'str'>
②json.dumps
作用:用于将Python对象编码成JSON字符串。
输出结果:
{"name": "666", "age": "18"} #注意,虽然转换后的结果跟转换前的结果一样,但是数据类型变了。
<class 'str'> #我们可以发现,看上去像是字典的形式,实际上已经成了JSON的str类型。
<class 'dict'>
经过上面两段程序,相比大家已经对JSON有了一定的了解,能理解JSON数据类型与python数据类型之间的转换过程。
那么我们来看看更多的转换数据类型。
时刻清楚这一点,JSON是一种数据类型,以str形式展现。