正则表达式
第九 正则表达式 【重要】
-
-
# 有了re模块就可以在python语言中操作正则表达式了
-
-
定义:一套规则---匹配字符串
-
应用:
# 1.检测一个输入的字符串是否合法 -- web开发项目 表单验证
# 用户输入一个内容的时候,我们要提前做检测
# 能够提高程序的效率并且减轻服务器的压力
# 2.从一个大文件中找到所有符合规则的内容 -- 日志分析\爬虫
# 能够高效的从一大段文字中快速找到符合规则的内容
-
正则的规则
# 所有的规则中的字符就可以刚好匹配到字符串中的内容
# 字符组 描述的是一个位置上能出现的所有可能性
# 接受范围,可以描述多个范围,连着写就可以了
# [abc] 一个中括号只表示一个字符位置
# 匹配a或者b或者c
[0-9a-zA-Z] # 根据ascii码表进行范围的比对
# ascii码表A-Z 65-90
# ascii码表a-z 97-122
-
# 在正则表达式中能够帮助我们表示匹配的内容的符号都是正则中的 元字符
[0-9] --> \d 表示匹配一位任意数字 digit
[0-9a-zA-Z] ---> \w 表示匹配数字字母下划线等价于 '[A-Za-z0-9_]' word
空格 --> 空格
tab --> \t # \t 是制表符
enter --> \n # \n 换行符
空格 ,tab ,回车 --> \s 表示所有空白 包括空格 tab和回车
[] 字符组 [^] 非字符组
[^a-zA-Z]是去匹配目标字符串中非a—z也非A—Z的字符
\W 非数字字母下划线等价于 '[^A-Za-z0-9_]'
\D 非数字
\S 非空白
[\d]等价于\d
[\d\D] [\w\W] [\s\S] 表示匹配所有
. 匹配除了换行符之外的所有
[^\d] 匹配所有的非数字 等价[^1]
^ 匹配一个字符串的开始
$ 匹配一个字符串的结尾
| (或) a表达式|b表达式 匹配a或者b表达式中的内容,如果匹配a成功了,不会继续和b匹配。所以,如果两个规则有重叠部分,总是把长的放在前面
() 分组 # 约束 | 描述的内容的范围问题
# www\.(oldboy|baidu|jd|taobao)\.com
字符含义:
-
量词
# {n} 表示匹配n次
# {n,} 表示匹配至少n次
# {n,m}表示至少匹配n次,至多m次
# ? 表示匹配0次或1次 {0,1}
# + 表示1次或多次 {1,}
# * 表示0次或多次 {0,}
整数 \d+
小数 \d+\.\d+
整数或小数 : \d+\.?\d*
分组的作用 :\d+(\.\d+)? #既能匹配整数又能匹配小数
# 匹配手机号
1[3-9]\d{9}
# 判断用户输入的内容是否合法,如果用户输入的对就能查到结果,如果输入的不对就不能查到结果
^1[3-9]\d{9}$
# 从一个大文件中找到所有符合规则的内容
1[3-9]\d{9}
# 贪婪匹配
# 在量词范围允许的情况下,尽量多的匹配内容
# .*x 表示匹配任意字符 任意多次数 遇到最后一个x才停下来
# 非贪婪(惰性)匹配
# .*?x 表示匹配任意字符 任意多次数 但是一旦遇到x就停下来
# a开头由至少一个字母组成的字符串
# ^a[a-zA-Z]*
# ^a.*
# 以1开头,中间3-5位数字,x结尾,中间的值不能超过5位
# 超过5位整个字符串都不能匹配
# 1\d{3,5}x
# 以1开头,中间3-5位数字,x结尾,中间的值不能超过5位
# 超过5位整个字符串都不能匹配
# ^1\d{3,5}x$
-
转义符
# 原本有特殊意义的字符,到了表达它本身的意义的时候,需要转义
# 有一些有特殊意义的内容,放在字符组中,会取消它的特殊意义
# [().*+?] 所有的内容在字符组中会取消它的特殊意义
# [a\-c] -在字符组中表示范围,如果不希望它表示范围,需要转义,或者放在字符组的最前面\最后面
# 18/15位的身份证号
[1-9]\d{16}[0-9x]|[1-9]\d{14}
import re
# findall返回列表 找所有的匹配项
ret = re.findall('\d+','19740ash93010uru')
print(ret)
# search 匹配就 返回一个变量,通过group取匹配到的第一个值,不匹配就返回None,group会报错
ret = re.search('\d+','19740ash93010uru')
print(ret) # 变量
if ret:
print(ret.group())
#为了findall可以顺利取到分组中的内容,有一种特殊的语法,就是优先显示分组内容,还是按照完整的正则进行匹配,只是显示括号匹配到的内容(加上括号 是为了对真正需要的内容进行提取)
# 取消分组优先(?: 正则表达式)
ret = re.findall('9(\d)\d','19740ash93010uru')
print(ret)
# search 还是按照完整的正则进行匹配,显示也显示匹配到的第一个内容,但我们可以通过给group方法传参数,来获取具体文组内容
ret = re.search('9(\d)(\d)','19740ash93010uru')
print(ret) # 变量
if ret:
print(ret.group())
print(ret.group(1))
print(ret.group(2))
# findall 取所有符合条件的,优先显示分组中的
# with open('douban.html',encoding='utf-8') as f:
# content = f.read()
# ret = re.findall('<span class="title">(.*?)</span>(?:\s*<span class="title">.*?</span>)?',content)
# print(ret)
# 如果我们要查找的内容在一个复杂的环境中
# 我们要查的内容并没有一个突出的 与众不同的特点 甚至会和不需要的杂乱的数据混合在一起
# 这个时候我们就需要把所有的数据都统计出来,然后对这个数据进行筛选,把我们真正需要的数据对应的正则表达式用()圈起来
# 这样我们就可以筛选出真正需要的数据了
# search 只取第一个符合条件的,没有优先显示这件事儿得到的结果是一个变量
# 变量.group() 的结果 完全和 变量.group(0)的结果一致
# 变量.group(n) 的形式来指定获取第n个分组中匹配到的内容
-
什么是爬虫?
通过代码获取到一个网页的源码
要的是源码中嵌着的网页上的内容 -- 正则表达式
import requests
ret=requests.get('https://movie.douban.com/top250?start=0&filter=')
print(ret.content.decode('utf-8'))
# 分组和findall的现象
# 为什么要用分组?
# 把想要的内容放分组里
# 如何取消分组优先
# 如果在写正则的时候由于不得已的原因 导致不要的内容也得写在分组里
# (?:) 取消这个分组的优先显示
import requests
import re
import json
def getPage(url):
response = requests.get(url)
return response.text
def parsePage(s):
com = re.compile(
'<div class="item">.*?<div class="pic">.*?<em .*?>(?P<id>\d+).*?<span class="title">(?P<title>.*?)</span>.*?<span class="rating_num" .*?>(?P<rating_num>.*?)</span>.*?<span>(?P<comment_num>.*?)评价</span>', re.S)
ret = com.finditer(s)
for i in ret:
yield {
"id": i.group("id"),
"title": i.group("title"),
"rating_num": i.group("rating_num"),
"comment_num": i.group("comment_num"),
}
def main(num):
url = 'https://movie.douban.com/top250?start=%s&filter=' % num
response_html = getPage(url)
ret = parsePage(response_html)
f = open("move_info7", "a", encoding="utf8")
for obj in ret:
print(obj)
data = json.dumps(obj, ensure_ascii=False)
f.write(data + "\n")
if __name__ == '__main__':
count = 0
for i in range(10):
main(count)
count += 25
import re
ret = re.split('\d+','alex222wusir')
print(ret)
ret = re.split('\d(\d)\d','alex123wusir') # ()具有优先级
print(ret)
import re
# sub 替换
ret = re.sub('\d+','H','alex123wusir456',1) # 可以放参数
print(ret)
import re
# subn 以元组形式返回替换了几个
ret = re.subn('\d+','H','alex123wusir456')
print(ret)
import re
# match 用户输入的内容匹配的时候,要求用户输入11位手机号码,^手机号正则$
# match('手机号正则$','123eva456taibai') 规定这个字符号必须是什么样的
# search('^手机号正则$','123eva456taibai') 用来寻找这个字符串中是不是含有满足条件的子内容
ret = re.match('\d+','123eva456taibai')
print(ret.group())
ret = re.search('^\d+','123eva456taibai')
print(ret.group())
import re
# compile -- 节省代码时间的工具
# 假如同一个正则表达式要被使用多次
# 节省了多次解析同一个正则表达式的时间
ret = re.compile('\d+')
res1 = ret.search('alex37176')
res2 = ret.findall('alex37176')
print(res1)
print(res2)
import re
# finditer -- 节省空间
ret = re.finditer('\d+','agks1ak018093')
for i in ret:
print(i.group())
import re
# 先compile(如果没有重复使用同一个正则,也不能节省时间)
# 再finditer
ret= re.compile('\d+')
res = ret.finditer('agks1ak018as093')
for r in res:
print(r.group())
# 列表不能用insert
# 列表不能用pop(n)
# 功能
# 性能
# 时间 :
# 你要完成一个代码所需要执行的代码行数
# 你在执行代码的过程中,底层程序是如何工作的
# 空间
# 是占用了宝贵的内存条资源
# 影响程序的执行效率
# 用户体验
-
分组命名
import re
ret = re.search('\d(\d)\d(\w+?)(\d)(\w)\d(\d)\d(?P<name1>\w+?)(\d)(\w)\d(\d)\d(?P<name2>\w+?)(\d)(\w)','123abc45678agsf_123abc45678agsf123abc45678agsf')
print(ret.group('name1'))
print(ret.group('name2'))
# (?P<名字>正则表达式)
# ret.group('名字')
-
分组命名的引用
import re
exp= '<abc>akd7008&(&*)hgdwuih</abb>008&(&*)hgdwuih</abc>' # </(?P=tag)> = /abb 取不到值 返回None
ret= re.search('<(?P<tag>\w+)>.*?</(?P=tag)>',exp)
print(ret)
import re
exp= '<abc>akd7008&(&*)hgdwuih</abc>008&(&*)hgdwuih</abd>'
ret= re.search(r'<(\w+)>.*?</\1>',exp)
print(ret)
ret= re.search('<(\w+)>.*?</\\1>',exp)
ret= re.search('<(\w+)>.*?</\w+>',exp)
print(ret)
import re
ret=re.findall(r"\d+\.\d+|(\d+)","1-2*(60+(-40.35/5)-(-4*3))")
print(ret)
ret = ['1', '2', '60', '', '5', '4', '3','','']
ret.remove('')
print(ret)
ret = filter(lambda n:n,ret)
print(list(ret))
# 分组命名(?P<组名>正则) (?P=组名)
# 有的时候我们要匹配的内容是包含在不想要的内容之中的,
# 只能先把不想要的内容匹配出来,然后再想办法从结果中去掉
# 匹配邮箱地址
# 邮箱规则
# @之前必须有内容且只能是字母(大小写)、数字、下划线(_)、减号(-)、点(.)
# @和最后一个点(.)之间必须有内容且只能是字母(大小写)、数字、点(.)、减号(-),且两个点不能挨着
# 最后一个点(.)之后必须有内容且内容只能是字母(大小写)、数字且长度为大于等于2个字节,小于等于6个字节
# taibai@oldboy..cn
# [-\w.]+@([-\da-zA-Z]+\.)+[a-zA-Z\d]{2,6}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)