正则表达式
-
正则表达式的作用:
- 数据的抓取,数据提取,如:抓取网站中的图片地址
- 数据清洗 ,把不雅的评论清洗掉
- 数据验证:验证手机号的合法性 11位数字
-
re模块
Python 提供的正则表达式处理模块 re,提供了各种正则表达式的处理函数
- 使用过程
1.导入模块:import re 2. 匹配:ret = re.match("正则表达式","要匹配的字符串") 3.判断是否成功: ret:不为空,表示匹配成功,返回的是match对象 为空,匹配失败 4.取匹配结果:ret.group() #注意:re.match()匹配以xxx开头的字符串
- 练习
#匹配ujiuye content = "ujiuye.com" import re ret = re.match("ujiuye",content) # print(ret) #<re.Match object; span=(0, 6), match='ujiuye'> if ret: print(ret.group()) else: print("匹配不成功")
-
匹配单个字符
- *1."." :表示匹配任意一个字符,除了\n(换行符)以外 (重点)
# ret = re.match("速度与激情","速度与激情") # ret = re.match("速度与.情","速度与即情") # ret = re.match("速度与.情","速度与#情") # ret = re.match("速度与.情","速度与\n情") # ret = re.match("速度与.情","速度与#情1") ret = re.match("速度与.情","速度与激情abc12345") print(ret)
- *2.[ ] :匹配"[ ]"中列举的字符 (重点)
# ret = re.match("速度与激情","速度与激情6") # ret = re.match("速度与激情[123456789]","速度与激情6") # ret = re.match("速度与激情[123456789]","速度与激情10") # ret = re.match("速度与激情[1-9]","速度与激情6") #速度与激情6不匹配 # ret = re.match("速度与激情[12345789]","速度与激情6") # ret = re.match("速度与激情[1-57-9]","速度与激情8") ret = re.match("速度与激情[a-z]","速度与激情c") print(ret)
- \d : 匹配数字,0-9 \D : 匹配非数字,即不是数字 (重点)
# 无论是速度与激情第几部,只要是数字,都算正确 # ret = re.match("速度与激情\d","速度与激情6") # ret = re.match("速度与激情\d","速度与激情#") # \D : 匹配非数字,即不是数字 # ret = re.match("速度与激情\D","速度与激情#") ret = re.match("速度与激情\D","速度与激情6") print(ret)
- 4.\s : 匹配空格 \S: 匹配非空格
# ret = re.match("速度与激情\s","速度与激情6") # ret = re.match("速度与激情\s","速度与激情 ") # ret = re.match("速度与激情\S","速度与激情6") ret = re.match("速度与激情\S","速度与激情") print(ret)
- \w 匹配单词字符:(a-z,A-Z,0-9,_) \W:匹配非单词字符
# ret = re.match("\w","1") # ret = re.match("\w","a") # ret = re.match("\w","#") # ret = re.match("\w","刘") ret = re.match("\W","刘") print(ret)
-
匹配多个字符 {m},{m,n},?,+,*
- 1.{m} :匹配前一个字符m次
#匹配手机号 #规则:要求满足11为数字,且第一位1 # ret = re.match("\d{11}","12345678901") # ret = re.match("\d{11}","1234567890") #None # ret = re.match("\d{11}","12345a78901") #None # ret = re.match("1\d{10}","12345678901") #12345678901 ret = re.match("1\d{10}","123456789011123") print(ret)
- 2.{m,n} : 匹配前一个字符m到n次
#匹配电话号码的合法性 如:010-1234567 ,0558-8080745 #规则:区号3-4位,电话号是7-8位,中间用“-”连接 # ret = re.match("\d{3,4}-\d{7,8}","010-1234567") # ret = re.match("\d{3,4}-\d{7,8}","0558-8080745") # ret = re.match("\d{3,4}-\d{7,8}","0558-80807455") ret = re.match("\d{3,4}-\d{7,8}","0558-8080745a") print(ret)
- ? :前一个字符出现0次或者1次,要么出现1次,要么出现0次 (重点)
#匹配电话号码的合法性 如:010-1234567 ,0558-8080745 #规则:区号3-4位,电话号是7-8位,中间用“-”连接,"-"可有可无 # ret = re.match("\d{3,4}-\d{7,8}","010-1234567") ret = re.match("\d{3,4}-?\d{7,8}","0101234567") #0101234567 # ret = re.match("\d{3,4}-?\d{7,8}","010-1234567") #010-1234567 print(ret)
-
4.*: 匹配前一个字符出现0次或者多次 (重点)
#案例:把一个文本内容全部提取出来 # content = "life is short,I use python !" content = "life is short\nI use python !" # ret = re.match(".*",content) ret = re.match(".*",content,re.S) #可以匹配多行 life is short\nI use python ! print(ret) print(ret.group())
-
5.+:匹配前一个字符出现1次或者多次,至少出现1次
# ret = re.match("a+","aaaa") #aaaa ret = re.match("a+","") #None ret = re.match("a*","") #'' print(ret)
-
匹配开头与结尾
- 1.“^”:匹配开头字符串
# ret = re.match("ujiuye","ujiuye.com") # ret = re.search("ujiuye","www.ujiuye.com") # ret = re.search("^ujiuye","www.ujiuye.com") #None ret = re.match("[^123]","1") #None print(ret) #^用在[]中,表示取反
- 2."$":匹配以xxx结尾的字符串
#匹配手机号 #规则:要求满足11为数字,且第一位1 # ret = re.match("1\d{10}","12345678901abc") #匹配成功但是不符合要求 ret = re.match("1\d{10}$","12345678901abc") #None print(ret)
-
匹配分组
- 1.| :匹配左右任意一个表达式
- 2.(ab):分组
email = "huangzhi@163.com" ret = re.match("(\w{4,20})@(163)\.(com)$",email) print(ret.group(0)) print(ret.group(1)) print(ret.group(2)) print(ret.group(3)) email_list = ["huangzhi@163.com","wangtao@163.cn","110123@qq.com","yuanle@163.com.cn","guyin@163ccom"] for email in email_list: ret = re.match("\w{4,20}@(163|qq)\.com$",email) if ret: print(f"{ret.group(0)}邮箱名合法") else: print(f"{email}邮箱名不合法")
- 3.引用分组,引用分组中的字符串 \num
#检查html网页语法的合法性 #语法规则:标签必须配对 content = "<h1>hello world</h1>" # content = "<h1>hello world</h2>" #不严谨的写法 # ret = re.match("<\w+>.*</\w+>",content) #严禁的写法 # ret = re.match("<(\w+)>.*</\\1>",content) ret = re.match(r"<(\w+)>.*</\1>",content) print(ret)
- 给分组起别名 (?P<name>)
# 给分组起别名 (?P<name>) content = "<h1><body>hello world</body></h1>" # ret = re.match("<(\w+)><(\w+)>.*</\\2></\\1>",content) ret = re.match("<(?P<a>\w+)><(?P<b>\w+)>.*</(?P=b)></(?P=a)>",content) print(ret)
-
re模块中的其他用法 search,findall,sub
# 1.search:查看匹配的数据,匹配到立即返回 #案例:匹配阅读次数 # content = "阅读次数是88次。" # ret = re.search("\d+",content) # print(ret) # print(ret.group()) # 2.findall:查找字符串中所有匹配的数据,返回列表 #匹配所有的数字 # content = "阅读次数是88次,下载次数是55次。" # ret = re.findall("\d+",content) # print(ret) #3.sub():替换,返回的是替换后的字符串 #将所有的次数归0 content = "阅读次数是88次,下载次数是55次。" ret = re.sub("\d+","0",content) print(ret)
-
贪婪和非贪婪
- python中默认是贪婪,总是尽可能多的匹配字符,非贪婪相反,总是尽可能少的匹配字符
# ret = re.match("\d{2,10}","123456789") ret = re.match("\d{2,10}?","123456789") #使贪婪模式变为非贪婪模式 print(ret)
2.字符串前面加“r”表示原生字符串
3.re.compile(strPattern)
pattern = re.compile("\d{2,10}") ret = pattern.match("123456789") print(ret)
迭代器
-
迭代:
- 迭代是访问集合元素的一种方式,可以将某个数据集内的数据“一个挨着一个的取出来”,就叫迭代
-
可迭代对象
- 可以通过for循环遍历取出元素的对象就是可迭代对象
- 通过isinstance()判断一个对象是否是可迭代对象
from collections import Iterable print(isinstance([],Iterable)) #True print(isinstance("",Iterable)) #True print(isinstance(123,Iterable)) #False
-
迭代器:拥有
__iter__
方法和__next__
方法的对象就是迭代器,帮助我们在迭代遍历时记录访问的位置,以便下一次迭代可以返回下一条数据 (重点)- iter()函数可以把可迭代对象中的迭代器取出来,内部调用
__iter__
方法 - next()函数通过迭代器获取下一位置的值,内部调用的是
__next__
方法
string = "hello" # for i in string: # print(i) #获取迭代器 iter1 = iter(string) # print(iter1) print(next(iter1)) print(next(iter1)) print(next(iter1)) print(next(iter1)) print(next(iter1)) print(next(iter1))
- iter()函数可以把可迭代对象中的迭代器取出来,内部调用
-
迭代器实现斐波那契数列 1,1,2,3,5,8
class Fib: def __init__(self,n): #n表示前n项数列 self.n = n self.a = 1 self.b = 1 self.index = 0 #记录位置 def __iter__(self): return self # pass def __next__(self): if self.index<self.n: num = self.a self.a,self.b = self.b,self.a+self.b self.index+=1 return num else: raise StopIteration fib = Fib(5) print(isinstance(fib,Iterable)) for i in fib: print(i)
生成器
概念:生成器的本质就是迭代器,但是比迭代器更优雅
生成器有两种:生成器函数和生成器表达式
-
生成器函数:一个包含yield关键字的函数就是生成器函数。yield不能和return共用 (重点)
生成器函数执行后会得到一个生成器作为返回值,并不会执行函数体。
执行了next()方法之后才会执行函数体,并且获得返回值
next()内置方法,内部调用的是
__next__
()方法yield和return相同的是都可以返回值,不同的是yield不会结束函数
-
send()
- send()获取下一个值的效果和next基本一致,只是在获取下一个值的时候,给上一个yield传递数据
- 注意:第一次使用生成器的时候,使用next方法获取下一个值
yield from 循环遍历容器类型
-
生成器表达式 (重点)
- 格式:将列表推导式[ ]改成( )即可
unitTest
单元测试:是用来对一个模块/一个函数/一个类来进行正确性检验的测试工作
-
单元测试的四个核心:
- test case(测试用例):一个py文件就是一个测试用例
- test suit(测试套件):测试用例的集合
- test runner(测试运行器):执行测试套件
- test fixture(测试脚手架)
-
test case(测试用例):一条用例就是一个完整的测试流程
步骤
- 1.导入unittest模块,被测文件中的类
- 2.创建一个测试类,继承unittest.TestCase
- 3.重写setUp和tearDown方法(初始化条件和结束条件)
- 4.定义测试函数,函数名以test_开头
- 5.在函数中使用断言来判断测试结果是否符合预期
- 6.调用unittest.main()方法运行测试用例,无此方法也可以运行
设置setUp和tearDown:每次用例执行前都会执行初始化条件和结束条件
python2 vs python3 (重点)
-
print
- python2中是输出语句
- python3 中是函数
-
range和xrange
- range()在python2中会得到一个列表,xrange(1,3)得到一个生成器
- 在python3中是生成器,没有xrange
-
字符串
- python2中存储字符串,底层使用的是ascii编码
- python3储存字符串,使用的是Unicode
-
异常处理
python2
try: print 1/0 except Exception,e: print e
-
打开文件
f = file()
f = file("1.txt","w") f.write("hello") f.close()
-
标准输入
python2有两种标准输入
info = raw_input("提示信息"),输入数据全部转换为字符串 info = input("提示信息:") ,输入什么数据就输出什么数据类型
-
除法操作
python2 /:表示的是整除,加上浮点数就是真实除法
python3:/表示除法,//表示整除