21天挑战学习-Day09正则表达式

发布于:2023-01-21 ⋅ 阅读:(415) ⋅ 点赞:(0)

目录

​一、正则表达式简介

 知识点1

 知识点2

二、匹配单个字符

 1.\d

2.[]

 三、匹配多个字符

1.{}

2.?

 四、案例一

1.初级版

 2.改善版

 五、案例二

1.初版

 2.改善版+分组等

六、html标签匹配分析

 七、re模块的高级用法

1.search()

 2.findall

3.sub 将匹配到的数据进行替换

 4.split

八、小应用

 九、贪婪和非贪婪

十.原始字符r

十一.拓展

十二.预告


活动地址:CSDN21天学习挑战赛

学习的最大理由是想摆脱平庸,早一天就多一份人生的精彩;迟一天就多一天平庸的困扰。各位小伙伴,如果您:
想系统/深入学习某技术知识点…
一个人摸索学习很难坚持,想组团高效学习…
想写博客但无从下手,急需写作干货注入能量…
热爱写作,愿意让自己成为更好的人…

​一、正则表达式简介

对数据进行筛选
import re
result = re.match(正则表达式, 要匹配的字符串)

 知识点1

import re
# re.match(正则表达式, 需要处理的字符串)
# 当字符串有满足正则表达式的数据时,才就会有返回值
# 即用户的输入符合你的规范
result = re.match(r"hello", "hello world")
print(result)  # <re.Match object; span=(0, 5), match='hello'>

当字符串有满足正则表达式的数据时,才就会有返回值。即用户的输入符合你的规范

 知识点2

result = re.match(r"[hH]ello", "Hello world")  # <re.Match object; span=(0, 5), match='Hello'>
print(result)

二、匹配单个字符

字符 功能
. 匹配任意1个字符(除了\n)如果想让"."包括"\n"re.match(r".*", "要解析的数据", "re.S")
[ ] 匹配[ ]中列举的字符
\d 匹配数字,即0-9
\D 匹配非数字,即不是数字
\s 匹配空白,即 空格,tab键
\S 匹配非空白
\w 匹配单词字符,即a-z、A-Z、0-9、_ 、各种语言
\W 匹配非单词字符

 1.\d

import re
result = re.match(r"速度与激情\d", "速度与激情9")  # 一个\d等价于一个数字
print(result)  # <re.Match object; span=(0, 6), match='速度与激情9'>
# 我怎么知道用户的哪部分数据符合规范---提取符合规范的数据
print(result.group())  # 速度与激情9

2.[]

import re
# []指这个位置为[]里面的任意数字
result = re.match(r"速度与激情[12345678]", "速度与激情9").group()
print(result)  # AttributeError: 'NoneType' object has no attribute 'group'报错即没有返回值
# 上式化简[1-8] = [12345678]
# [123678] = [1-36-8]注意[]只是占了一位
import re


result = re.match(r"速度与激情[1-8abcd]", "速度与激情a").group()


# [1-8a-zA-Z]判断1-8 a-z A-Z
# \w 即:world词的意思 等价于"0-9 a-z A-Z _ 各种语言"
# \s 等价于"空格(space) Tab键"--即判断空白字符
# 所有的大写的如\W(不是那些"0-9 a-z A-Z _ 各种语言") \S(非空白) \D(非数字)都与小写相反
# "."----最宽广,代表任意字符但是不可以匹配\n
# 总结:匹配单字符有"/d /s . /w /W /S /D"

 三、匹配多个字符

字符 功能
* 匹配前一个字符出现0次或者无限次,即可有可无
+ 匹配前一个字符出现1次或者无限次,即至少有1次
? 匹配前一个字符出现1次或者0次,即要么有1次,要么没有
{m} 匹配前一个字符出现m次
{m,n} 匹配前一个字符出现从m到n次

1.{}

import re 
result = re.match(r"速度激情\d{1,2}", "速度激情18").group()
# {1,2}指与其紧挨着的有 1到2个包括1个和2个
print(result)

2.?

import re
re.match(r"/d{11}", "18956423656")  # 必须为11位连续的数字
re.match(r"021-?\d{8}", "021-12345678")  # "-"在拨电话的时候可以没有所以?表示左边的可有可无
re.match(r"\d{3,4}-?\d{7,8}", "021-12345678")

3.其它

"*"号前面的可以有任意多个如".*"--->任意多个任意字符(.就只不可以匹配\n)
如果想让"."包括"\n"re.match(r".*", "要解析的数据", "re.S").group()  # 多传入参数"re.S"
".+"--->"+":表示前面的至少有一个

 四、案例一

1.初级版

"""
判断:
    names = ["name1", "_name", "2_name", "_name__"]里面的各项是否满足python命名规范
"""
import re
names = ["name1", "_name", "2_name", "_name__", "_name#", "_@"]
for i in names:
    result = re.match(r'[a-zA-Z_][a-zA-Z0-9_]*', i)
    if result:
        print("%s满足编程语言命名规则,通过正则匹配出来的数据是%s" % (i, result.group()))
    else:
        print("%s不满足编程语言命名规则" % i)

补充:

import re
result = re.match(r"x", "速度与激情9")
print(result)

结果打印:None

import re
result = re.match(r"速度与激情9", "速度与激情9")
ret = result.group()
print(ret)

结果打印:速度与激情9

即group将匹配到的数据打印出来

 2.改善版

import re
names = ["name1", "_name", "2_name", "_name__", "_name#", "_@"]
for i in names:
    # 问题:我想他匹配完了以后正好是本字符串的全部
    # 结果:_@不满足编程语言命名规则
    result = re.match(r'[a-zA-Z_][a-zA-Z0-9_]*$', i)
    if result:
        print("%s满足编程语言命名规则,通过正则匹配出来的数据是%s" % (i, result.group()))
    else:
        print("%s不满足编程语言命名规则" % i)

# 总结:match()默认判断开头但不会判断结尾,想要判断结尾在结尾加$想要判断开头在开头加^
# 即最正规的正则写法 re.match(r'^[a-zA-Z_][a-zA-Z0-9_]*$', i)

总结:match()默认判断开头但不会判断结尾,想要判断结尾在结尾加$想要判断开头在开头加^

 五、案例二

1.初版

"""
判断12306邮箱地址:
    @符号之前有4-20位[英文,数字,_]例如:hello@163.com
"""
import re


def main():
    # 用户输入邮箱地址
    name = input("请输入163邮箱地址:")
    # 自动判断是否合格
    result = re.match(r"^[a-zA-Z0-9_]{4,20}@163\.com$", name)  # 注意"."代表任意字符串(除\n)所以由题意这里要"\."进行转义
    if result:
        print("%s符合" % name)
    else:
        print("%s不符合" % name)


if __name__ == "__main__":
    main()
# 总结:正则中如果出现了特殊字符如本程序中的"."要进行转义才符合

总结:正则中如果出现了特殊字符如本程序中的"."要进行转义才符合

 2.改善版+分组等

"""
原代码只是判断163.com的那如何判断126的甚至qq的
"""
import re


def main():
    name = input("请输入163邮箱地址:")
    # 解决方法:(163|126) "|"为"或"的意思
    result = re.match(r"(^[a-zA-Z0-9_]{4,20})@(163|126)\.com$", name)
    if result:
        print("数据%s符合的为%s" % (name, result.group(1)))
    else:
        print("%s不符合" % name)


if __name__ == "__main__":
    main()
"""
()的作用本程序起到了限定的作用,还可以取出特定值的作用
    如:hello@163.com
    result = re.match(r"^[a-zA-Z0-9_]{4,20}@(163|126)\.com$", name).group(1)
    result = "163" 只要正则表达式成功group()都可以取值,
        如果想取部分的值里面有()就行,如:
        result = re.match(r"(^[a-zA-Z0-9_]{4,20})@(163|126)\.com$", name).group(1)
        result = hello
        
        result = re.match(r"(^[a-zA-Z0-9_]{4,20})@(163|126)\.com$", name).group(2)
        result = 163
        
        result = re.match(r"(^[a-zA-Z0-9_]{4,20})@(163|126)\.com$", name).group(2)
        这个情况程序会崩......
"""

要点:

1.(163|126) "|"为"或"的意思

2.()的作用本程序起到了限定的作用,还可以取出特定值的作用
    如:hello@163.com
    result = re.match(r"^[a-zA-Z0-9_]{4,20}@(163|126)\.com$", name).group(1)
    result = "163" 只要正则表达式成功group()都可以取值,
        如果想取部分的值里面有()就行,如:
        result = re.match(r"(^[a-zA-Z0-9_]{4,20})@(163|126)\.com$", name).group(1)
        result = hello
        
        result = re.match(r"(^[a-zA-Z0-9_]{4,20})@(163|126)\.com$", name).group(2)
        result = 163
        
        result = re.match(r"(^[a-zA-Z0-9_]{4,20})@(163|126)\.com$", name).group(2)
        这个情况程序会崩......

六、html标签匹配分析

result = re.match(r"^<\w*>.*</\w*>$", html_str) 
# 问题在于这个不可以限定h1左右都相等,左右没有关系

 如何才可以使其正确的匹配呢 ?

result = re.match(r"^<(\w*)>.*</\1>$", html_str)

# \1代表正则表达式里面第一组分组里面的值 # print(result.group())

result = re.match(r"^<(\w*)><(\w*)>.*</\2></\1>$", "<body><h1>hahaha</h1></body>") 
# \1代表正则表达式里面第一组分组里面的值\2表示第二个分组里面的
print(result.group())  # <body><h1>hahaha</h1></body>

 拓展——分组起别名

给分组起名(?P<name>)  引用别名为name分组分配到的字符串(?P=name)
result = re.match(r"^<(?P<one>\w*)><(?P<two>\w*)>.*</(?P=two)></(?P=one)>$", "<body><h1>hahaha</h1></body>")  # \1代表正则表达式里面第一组分组里面的值
print(result.group())  # <body><h1>hahaha</h1></body>

 七、re模块的高级用法

1.search()

re模块的match()会匹配所有数据但是有时候不需要提取所有,只需要提取部分的数据罢了
此时用search

import re
result = re.search(r"\d+", "1024阅读次数为999")
# 特点拿数据去匹配,匹配到第一个就直接返回数据不再管之后的了
print(result.group())  # 1024

 2.findall

import re
result = re.findall(r"\d+", "1024阅读次数为999")  # 直接返回数据不需要用group()
print(result)  # ['1024', '999']

3.sub 将匹配到的数据进行替换

import re 
re.sub(正则表达式, 替换的数据, 起始数据)
result = re.sub(r"\d+", "222", "1024阅读次数为999")  # 直接返回数据不需要用group()
print(result)  # 222阅读次数为222

高级1

import re


def add(temp):
    strNum = temp.group()
    num = int(strNum) + 1
    return str(num)


ret = re.sub(r"\d+", add, "python = 997")
print(ret)

ret = re.sub(r"\d+", add, "python = 99")
print(ret)

 解析:替换的内容是一个函数,它把匹配到的数据当成参数传入同时进行一定的运算然后再进行替换。

结果:

python = 998
python = 100

 4.split

split 根据匹配进行切割字符串,并返回一个列表

 需求:切割字符串"info:xiaoZhang 33 shandong"

import re

ret = re.split(r":| ", "info:xiaoZhang 33 shandong")  # 切割":"或"space(空格)"
print(ret)  # ['info', 'xiaoZhang', '33', 'shandong']

八、小应用

import re
a ="""<div class="job-detail">我们是一群什么样的人?
<br>我们是一群有灵魂的代码写手,希望通过代码改变产品、改变世界;
<br>我们渴望取得商业价值的成功,通过代码提供高质量的产品给到客户;
<br>我们钦佩拥有深厚算法和数据结构工地的工程师,然而世界的复杂性却远比这样的知识更加复杂,我们希望能够在世界的复杂性中找到极限简单的真谛;
<br>这是一群致力于改变,敢于迎接挑战的人,期待你和我们一起改变世界。
<br>
<br>职位诱惑:
<br>真正的工程师文化,优质团队
<br>我们想找玩转源码的同类人,而非只会用框架的大多数~
<br>
<br>工作职责:
<br>配合团队其他成员进行模块开发及整合
<br>独立完成后台服务功能模块的设计与开发
<br>开发和维护自动化运维工具
<br>开发和维护谷露招聘管理系统
<br>
<br>任职要求:
<br>具备扎实的语言、数据结构、数据库、网络等基础知识;
<br>逻辑条理性强,具备良好的沟通能力 ;
<br>熟悉web开发优先 ;
<br>Full Stack优先 ;
<br>有项目经验优先 ;
<br>热爱技术,追求**者优先。</div>"""
result = re.sub(r"<[^>]*>|&nbsp;|\n", "", a)
print(result)
# ^匹配字符串的开头

 补充:&nbsp是html里面的空格字符

结果:

我们是一群什么样的人?我们是一群有灵魂的代码写手,希望通过代码改变产品、改变世界;我们渴望取得商业价值的成功,通过代码提供高质量的产品给到客户;我们钦佩拥有深厚算法和数据结构工地的工程师,然而世界的复杂性却远比这样的知识更加复杂,我们希望能够在世界的复杂性中找到极限简单的真谛;这是一群致力于改变,敢于迎接挑战的人,期待你和我们一起改变世界。职位诱惑:真正的工程师文化,优质团队我们想找玩转源码的同类人,而非只会用框架的大多数~工作职责:配合团队其他成员进行模块开发及整合独立完成后台服务功能模块的设计与开发开发和维护自动化运维工具开发和维护谷露招聘管理系统任职要求:具备扎实的语言、数据结构、数据库、网络等基础知识;逻辑条理性强,具备良好的沟通能力 ;熟悉web开发优先 ;Full Stack优先 ;有项目经验优先 ;热爱技术,追求**者优先。

 九、贪婪和非贪婪

Python里数量词默认是贪婪的,总是尝试匹配尽可能多的字符;非贪婪则相反,总是尝试匹配尽可能少的字符。在"*","?","+","{m,n}"后面加上?,使贪婪变成非贪婪。

>>> s="This is a number 234-235-22-423"
>>> r=re.match(".+(\d+-\d+-\d+-\d+)",s)
>>> r.group(1)
'4-235-22-423'
>>> r=re.match(".+?(\d+-\d+-\d+-\d+)",s)
>>> r.group(1)
'234-235-22-423'
>>>

正则表达式模式中使用到通配字,那它在从左到右的顺序求值时,会尽量“抓取”满足匹配最长字符串,在我们上面的例子里面,“.+”会从字符串的启始处抓取满足模式的最长字符,其中包括我们想得到的第一个整型字段的中的大部分,“\d+”只需一位字符就可以匹配,所以它匹配了数字“4”,而“.+”则匹配了从字符串起始到这个第一位数字4之前的所有字符。

解决方式:非贪婪操作符“?”,这个操作符可以用在"*","+","?"的后面,要求正则匹配的越少越好。

>>> re.match(r"aa(\d+)","aa2343ddd").group(1)
'2343'
>>> re.match(r"aa(\d+?)","aa2343ddd").group(1)
'2'
>>> re.match(r"aa(\d+)ddd","aa2343ddd").group(1) 
'2343'
>>> re.match(r"aa(\d+?)ddd","aa2343ddd").group(1)
'2343'
>>>

十.原始字符r

print('\\n')  # \n
print(r'\n')  # \n
print('\n')  # 输出一个空行

 从上面的代码可以知道python官方定义了很多具有特殊功能的东西比如换行的时候“\n”那我们如何使他们失去这些特殊的功能呢,这个时候就用r"\n"解决使它成为字符串意义上的\n。

import re
mm = "c:\\a\\b\\c"  # "c:\\a\\b\\c"
ret = re.match("c:\\\\", mm).group()  # c:\\和"c:\\a\\b\\c"匹配
print(ret)  # print("c:\\")  所以最后输出c:\

 ret = re.match("c:\\", mm).group()这行代码里面首先解释器看到了c:\\,我靠它就想""不是特殊字符----转义字符吗?所以两个\输出一个\。所以最后拿去匹配的时候实际上是c:\,然后你保存为变量ret,接下来输出的时候也被去掉一个""最后输出c:\。而如果你换为一下这个代码

import re
mm = "c:\\a\\b\\c"  # c:\\a\\b\\c
ret = re.match(r"c:\\", mm).group()  # c:\\和c:\a\b\c匹配结果为c:\\
print(ret)  # c:\ 因为print("c:\\")输出c:\

你只需要r"c:\"里面c:\就得出来了一样的结果。因为解释器运行到这里的时候发现了r"",然后它就知道里面的东西不要当作特殊符号对待,而应该直接拿去匹配。

 总结:

对于匹配部分和输出的时候如果不用原始字符就会对特殊的进行相应转换再拿去匹配,

re.match(r"匹配部分", "原始部分")

原始部分你即使有特殊的字符也不会进行转换而是直接拿去匹配

十一.拓展

import re
result = re.match(r'[^:]+', "na:dsd")
print(result.group())
# [^:]表示匹配除:之前的所有字符

结果:na

十二.预告

因为之前耽误了挺多进度,所以看今天晚上有时间就赶一下进度。

明天复习web服务器相关的东西。


网站公告

今日签到

点亮在社区的每一天
去签到