1.正则表达式
1.什么是正则表达式?
把它当做一个特殊的字符串,帮助进行检索,验证查询等行为
作用:对字符串内容进行验证
regular expression ---> 正则表达式 规则表达式 正规表达式
2.正则表达式的使用场景
网站的用户名
密码
邮箱格式
手机号……验证
爬虫筛选数据
3.使用规则
正则表达式适用于处理字符串的强大工具,拥有自己独特的语法[不管哪门编程语言 语法规则都是一致的] 和一个单独针对于正则表达式的处理引擎。虽然处理字符串的效率比原生的字符串方式要低,但是比原生字符串的功能强大
例如:在一个字符串中找到所有的数字
如果使用原生的方式:遍历 判定
使用正则表达式:[0-9] + find()
4.Python中正则表达式的使用
需要引入模块 re
常用的方式:
compile(content)
根据字符串格式正则表达式 生成一个正则表达式对象
正则表达式对象.match(content)
根据字符串的正则表达式 去对指定内容进行匹配
匹配规则: 从左向右进行重叠验证 只要能重叠上 返回的就是Match对象 否则返回None
import re
# 根据字符串生成一个正则表达式对象
patternObj = re.compile("hello")
res = patternObj.match("hello nice to meet you")
print(res)
'''
<_sre.SRE_Match object; span=(0, 5), match='hello'>
span ---> 表示的是匹配到内容的字符区间 [start, stop)
match ---> 表示的是匹配到的内容
'''
# 获取匹配到的内容
content = res.group()
print(content)
# 获得区间
pos = res.span()
print(pos)
正则表达式对象.search(content)
在字符串中查询正则表达匹配的内容 如果查询到 返回第一个匹配的Match对象 否则返回None
import re
# 生成正则表达式对象
pobj = re.compile("cat")
res = pobj.search("i have a cat you have a dog he have a cat")
print(res)
# 范围
pos = res.span()
print(pos)
# 内容
content = res.group()
print(content)
'''
<re.Match object; span=(9, 12), match='cat'>
(9, 12)
cat
'''
正则表达式对象.findall(content)
在字符串中查询正则表达匹配的内容 返回的是一个列表 列表中放置的是根据正则表达式查询到的内容
[0-9] ---> 匹配的是0-9中任意一个数字
+ ---> 前面符号出现的次数 至少出现一次
import re
# [0-9]+这个数字连续至少出现一次 abc12abc
pobj = re.compile("[0-9]+")
res = pobj.findall("i12love34you78like2position127")
print(res) # ['12', '34', '78', '2', '127']
list0 = [int(item) for item in res]
print(list0) # [12, 34, 78, 2, 127]
res = sum(list0)
print(res) # 253
pobj = re.compile("[a-zA-Z0-9]+")
res = pobj.findall("i12love34you78like2position127,1234")
print(res) # ['i12love34you78like2position127', '1234']
正则表达式语法
单个字符匹配语法:
. ---> 通配符:匹配的是除了\n之外任意一个字符
英文语句中句号就是一个 .
在正则表达式中 . 具有特殊的含义 想匹配点的本意(英文句号)
设定范围 --- 使用[] --- 匹配的是中括号中任意一个字符:
匹配任意一个数字 [0-9] [1-5]
匹配小写英文字母 [a-z]
匹配大写英文字母 [A-Z]
匹配字母和数字 [a-zA-Z0-9]
不是连续的区间 需要一一列举 [amo]
如果在中括号的第一个字符是 ^ 表示的是范围取反
[^0-9] ---> 除了数字之外的任意一个字符
\d ---> [0-9]
\D ---> [^0-9]
\s ---> 匹配的是任意一个空白符号: \t \n \r 空格
\S ---> 匹配非空白中任意一个字符
\w ---> 匹配的是数字 字母 下滑线 和中文字符串中任意一个字符
\W ---> 对\w取反
在window下 \ ===> \\
对\转义 相当于对\\转义 所以需要\\\\
避免复杂性,借助于r ---> r"\\" ===> \\\\
设定匹配的字符串以指定内容开头 以指定内容结尾
^x ---> 以x开头
^[0-9] ---> 以数字开头
x$ ---> 以x结尾
[0-9]$ ---> 以数字结尾
关于数量词的符号
x* ---> 表示x出现任意次 可有可无[贪婪匹配]
[0-9]* ---> 表示数字出现任意次
如果字符串中没有自定的内容 代表的是没有匹配到具体的内容 但是不表示匹配失败
x+ ---> 表示x至少出现1次[贪婪匹配]
[0-9]+ ---> 数字至少连续出现1次
x? ---> 表示x最多出现1次 限制贪婪的
x*?
x+?
x{m, n} ---> x最少 出现m次 最多出现n次
x{m,} ---> x最少出现m次
x{m} ---> x只能出现m次
匹配分组()
用小括号包含的就是一个整体 匹配的时候必须和这个整体完全一致才可以
qq.com
163.com
126.cn
.net
(qq)
使用| ---> 表示或者的意思
^[0-9A-Za-z_]{6,16}@(qq|163|126)\.(com|cn|net)$
一个要匹配的内容已经确定格式 最好添加上开头符 和 结尾符
\num模式
是与分组结合使用的,如果后面分组根据正则表达式匹配之后的内容与前面分组根据正则表达式匹配到的内容是一致的情况下,可以使用\num简化正则表达式的写法
html ---> 文本标签
<起始标签>标签内容</结束标签>
起始标签的内容与结束的标签的内容是一致的
<html></html>
\b ---> 表示以指定内容为边界
可以是起始位置 可以是结束位置 空白两边
"cat dog"
\bcat\b
\B ---> 表示不以指定内容为边界
import re
pobj = re.compile(r"^[0-9a-zA-Z]test[0-9]$")
'''
加上头和尾:
限制了字符串的长度并且限制的字符串的开头和结尾
'''
res = pobj.match("1test2")
print(res)
pobj = re.compile(r"[0-9]?")
res = pobj.match("abc")
print(res)
'''
<div>very good</div>
'''
pobj = re.compile(r"<div>.*?</div>")
res = pobj.match("<div>very good</div></div></div></div>")
print(res)
def check_eamil(email_str):
pobj = re.compile(r"^[0-9A-Za-z_]{6,16}@(qq|163|126)\.(com|cn|net)$")
res = pobj.match(email_str)
if res != None:
return True
else:
return False
res = check_eamil("xiao@qq.com")
print(res)
'''
练习:
1.用户名验证:
不能包含 %&*$#@ 最少10位 最多16位
2.密码验证:
6-16位 只能包含数字 字母 下滑线
3.验证字符串内容是否是纯汉字
汉字的正则表达式范围[\u4e00-\u9fa5]
正则表达式中不要随意加空格
'''
def check_username(username):
pobj = re.compile(r"^[^%&*$#@]{10,16}$")
result = pobj.match(username)
if result != None:
return True
else:
return False
res = check_username("xiaomu1102%$$")
print(res)
def check_psw(password):
pobj = re.compile(r"^[0-9a-zA-Z_]{6,16}$")
result = pobj.match(password)
if result != None:
return True
else:
return False
def is_chinese(src):
pobj = re.compile(r"^[\u4e00-\u9fa5]+$")
result = pobj.match(src)
if result != None:
return True
else:
return False
res = is_chinese("你好")
print(res)
str0 = "cati have acat you have acats"
pobj = re.compile(r"\Bcat\B")
res = pobj.search(str0)
print(res)
# re.I 忽略大小写模式
pobj = re.compile(r"<([a-z]+)><([a-z]+)>.*?</\2></\1>", re.I)
res = pobj.match("<HTML><head>balabalabala</head></html>")
print(res)
split
根据正则表达式匹配到的内容 作为切割符 去切割字符串
import re
str0 = "hello1nice2to3you"
# 字符串的原方法中 切割字符串 不支持正则表达式
# 利用切割的方法 查找字符串中的数值 求和
pobj = re.compile(r"[^0-9]+")
res = pobj.split(str0)
print(res) # ['', '1', '2', '3', '']
lis0 = [int(item) for item in res if item.isdigit()]
print(lis0) # [1, 2, 3]
sub ---> 替换
import re
str0 = "我们是Python1811的学生 总人数为70"
# 要求把所有数字替换成0
pobj = re.compile(r"[0-9]+")
res = pobj.sub("0", str0)
print(res) # 我们是Python0的学生 总人数为0
# 可以接受函数 将函数返回结果作为替换值
# 接受一个参数 根据正则表达式匹配到的Match对象
# 可以传入函数 根据返回结果替换指定内容
def test(con):
print(con)
match_item = con.group()
if match_item == "1811":
return "1812"
else:
return "0"
pobj = re.compile(r"[0-9]+")
res = pobj.sub(test, str0)
print(res)
'''
<re.Match object; span=(9, 13), match='1811'>
<re.Match object; span=(21, 23), match='70'>
我们是Python1812的学生 总人数为0
'''
2.pygame写的游戏
球球大作战
游戏规则:
生成球:
点击屏幕任意位置 以该位置为圆心 半径随机 速度随机 颜色随机的球
大球吃小球
import pygame
import random
class Color:
@classmethod
def random_color(cls):
red = random.randint(0, 255)
green = random.randint(0, 255)
blue = random.randint(0, 255)
return (red, green, blue)
class Ball:
def __init__(self, cx, cy, radius, sx, sy, color):
self.cx = cx
self.cy = cy
self.radius = radius
self.sx = sx
self.sy = sy
self.color = color
self.is_alive = True # 球的默认存活状态
# 行为:
# 移动:在哪里移动
def move(self, window):
self.cx += self.sx
self.cy += self.sy
# 圆心点发生变化 需要做边界判断
# 横向出界
if self.cx - self.radius <= 0 or self.cx + self.radius >= window.get_width():
self.sx = -self.sx
# 纵向出界
if self.cy - self.radius <= 0 or self.cy + self.radius >= window.get_height():
self.sy = -self.sy
# 吃其他球
def eat_ball(self, other):
if self != other and self.is_alive and other.is_alive:
# 吃到其他球的条件 两者圆心点的距离 < 两者半径之和
distance = ((self.cx - other.cx) ** 2 + (self.cy - other.cy) ** 2)
if distance < ((self.radius + other.radius) ** 2) and self.radius > other.radius:
# 吃其他球
other.is_alive = False
# 自身半径在被吃球的半径的基础上增加0.14
self.radius += int(other.radius * 0.14)
# 出现对应 在界面上画出对应的一个球
def draw(self, window):
pygame.draw.circle(window,self.color,(self.cx, self.cy),self.radius)
if __name__ == '__main__':
# 画质屏幕
pygame.init()
# 设置屏幕
screen = pygame.display.set_mode((1400, 700))
# 设置屏幕标题
pygame.display.set_caption("大球吃小球")
# 定义一容器 存放所有的球
balls = []
isrunning = True
while isrunning:
for event in pygame.event.get():
if event.type == pygame.QUIT:
isrunning = False
# 点击屏幕任意位置 1表示点击左键
if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
pos = event.pos
# 圆心点
cx = pos[0]
cy = pos[1]
# 半径 10-100
radius = random.randint(10, 50)
# 速度
sx, sy = random.randint(-5, 5), random.randint(-5, 5)
# 颜色
color = Color.random_color()
# 根据以上信息创建球
x_ball = Ball(cx, cy, radius, sx, sy, color)
balls.append(x_ball)
# 刷漆
screen.fill((255, 255, 255))
# 遍历容器
for b in balls:
if b.is_alive:
b.draw(screen)
else:
balls.remove(b)
# 渲染
pygame.display.flip()
# 设置动画的时间延迟
pygame.time.delay(50)
for b in balls:
b.move(screen)
for b1 in balls:
b.eat_ball(b1)