Python字符串过滤器:正则表达式Regular Expression
一、什么是正则表达式
正则表达式是按照正确的既定规则、一种全语言类型Python、Java、JavaScript、PHP通用的表达式。
用途:
(1)根据规则抓取数据:配合爬虫、根据规则在文本中提取数据
(2)根据规则验证数据:验证手机号、验证邮箱、验证身份证
二、如何在Python中使用正则表达式
在Python中正则表达式的1个模块+2个方法需要学习
re模块 re=regular expression
import re
re方法一:根据规则查找/提取内容
re.findall(查找规则,匹配内容)
返回结构化数据,两个参数,形式参数为pattern(规律)string(需要查找/匹配的字符串)
re方法二:根据规则匹配/验证内容
re.match(匹配规则,匹配内容)
返回布尔,两个参数,形式参数为pattern(规律)string(验证字符串)
三、正则表达式的规则
正则表达式普通字符:
(1)普通字符是我们常规认识的a-z A-Z 0-9中文以及标点符号
正则表达式特殊符号/通配符/元字符,常用特殊字符包含:
(1)直接规则字符:. + * ? \d \D \w \W \s \S ^
(2)辅助规则字符(){} []
这几个括弧不是数据类型
字符代表含义
| . | 匹配除了换行以外的任何一个字符 |
| + | 匹配前边子表达式规则字符任意次数(至少出现一次) |
| * | 匹配前边子表达式规则字符任意次数包含0次 |
| ? | 尽可能少匹配,禁止贪婪模式 |
| \d | 匹配一个数字 |
| \D | 匹配一个非数字 |
| \w | 匹配包括下划线的任何单词字符 |
| \W | 匹配任何非单词字符 |
| \s | 匹配任何空白字符 |
| \S | 匹配任何非空白字符 |
| ^ | 字符串开头匹配 |
| $ | 字符串结束匹配 |
| [] | 筛选条件 |
| \b | 代表单词的开始或者结束(以标点、空格、换行作为分割) |
| \B | 匹配不位于单词开始或结束位置的空字符串 |
| () | 分组(作为一个整体) |
| {m,n} | 匹配前一个元字符m到n次 |
| \\ | 转移字符,跟在其后的字符将失去作为特殊元字符的含义 |
特别注意^符号与[]搭配使用代表"非" 如[^a],非a全取
举例:任务提起老师的姓名
import re
txt='''万门大学老师:宁夫
万门大学老师:正正
万门大学老师:陪陪'''
pattern=r":.*"
res=re.findall(pattern,txt)
print(res)
输出结果:

import re
txt='''万门大学老师:宁夫
万门大学老师:正正
万门大学老师:陪陪'''
pattern=r":(.*)"
res=re.findall(pattern,txt)
print(res)
输出结果:

举例:匹配日期
import re
pattern = re.compile(r"\d{4}年\d{2}月\d{2}日")
years='''
1900-02-10
1990-03-29
1991-03-31
1901年02月10日
1991年03月29日
1992年03月31日
'''
result=re.findall(pattern, years)
print(result)
输出结果:

import re
pattern = re.compile(r"\d{4}[年-]\d{2}[月-]\d{2}")
years='''
1900-02-10
1990-03-29
1991-03-31
1901年02月10日
1991年03月29日
1992年03月31日
'''
result=re.findall(pattern, years)
print(result)
输出结果:

info="姓名:boddy 生日:1987年10月1日 本科:2005年9月1日"
#match方法是从字符串最开始匹配
#贪婪匹配
match_result1=re.match(".*生日.*\d{4}",info)
print(match_result1.group())
#非贪婪匹配
match_result2=re.match(".*生日.*?\d{4}",info)
print(match_result2.group())
match_result3=re.match(".*生日.*?(\d{4}).*本科.*?(\d{4})",info)
print(match_result3.group(1))
print(match_result3.group(2))
match_result4=re.sub("\d{4}","2019",info)
print(info)
print(match_result4)
match_result5=re.search("生日.*?(\d{4}).*本科.*?(\d{4})",info)
print(match_result5.group(1))
print(match_result5.group(2))
输出结果:

re匹配模式IGNORECASE 忽略大小写,DOTALL忽略回车换行符
name1="my name is Bobby"
print(re.search("bobby", name1,re.IGNORECASE).group())
name2='''my name is '
bobby'''
print(re.match(".*bobby", name2,re.DOTALL).group())
输出结果:

举例:提取电话号码
import re
info='''mike,18391911111,39
lin,13932111111,40
danial,15932431115,45
frank,1A932431115,45'''
pattern=r"\d{11}"
result=re.findall(pattern,info)
print(result)
输出结果:

这里的\d{11}表示的是连续11个数字字符
举例:验证qq邮箱是否合法
import re
qq="78929302@qq.com"
pattern=r"[1-9][0-9]{4,10}@qq.com"
result=re.match(pattern,qq)
print((bool(result)))
QQ号第一位1-9数字,第二位为0-9数字且连续出现4-10次,后面@qq普通字符直接匹配
输出结果:

举例:最基础的普通字符正则表达式
import re
txt="万门大学"
pattern=r"万门"
result=re.findall(pattern,txt)
print(result)
输出结果:

举例:通配.遇到一个通配一个
import re
txt="万门大学"
pattern=r"."
result=re.findall(pattern,txt)
print(result)
输出结果:

import re
txt="""
我在万门学Python
我在万门学java
我在万门学Django
我在万门学PPT
"""
pattern=re.compile(r"学.") #compile编译的意思,编译当前的表达式
result=pattern.findall(txt)
print(result)
输出结果:

import re
txt="""
我在万门学Python
我在万门学java
我在万门学Django
我在万门学PPT
"""
pattern=re.compile(r"学.*") #compile编译的意思,编译当前的表达式
result=pattern.findall(txt)
print(result)
输出结果:

import re
txt="""
我在万门学Python
我在万门学java
我在万门学Django
我在万门学PPT
"""
pattern=re.compile(r"学.+") #compile编译的意思,编译当前的表达式
result=pattern.findall(txt)
print(result)
输出结果:

+号是需要满足至少出现一个才会生效表达式
import re
txt="""
我在万门学Python
我在万门学java
我在万门学Django
我在万门学PPT
我在万门学
"""
pattern1=re.compile(r"学.+") #compile编译的意思,编译当前的表达式
result1=pattern1.findall(txt)
print(result1)
pattern2=re.compile(r"学.*") #compile编译的意思,编译当前的表达式
result2=pattern2.findall(txt)
print(result2)
输出结果:

举例:{}匹配指定次数{3}指定3次{2,5}指定2-5次范围。()数据分组。^从头取值。$从尾巴取值。
import re
txt='''
我是你的正正老师
13800001111
13300001111
13400
136123123
1510000134
万门大学
.*.*&#$
'''
pattern1=r'.{3}' #.任何字符{3}要满足3个任意字符(.)联在一起
result1=re.findall(pattern1,txt)
print(result1)
输出结果:

^规定数据从头开始取值,按行取值用re.M=Multilines多行取法,就是一行一行取
import re
txt="""张三 python工程师
李四 java工程师
王五五 前端工程师"""
# findall()函数的参数 re.M=Multilines多行取法,就是一行一组取
# ^规定从头开始取
pattern1=r'^.{2,3}' #.任何字符{3}要满足3个任意字符(.)联在一起
result1=re.findall(pattern1,txt,re.M)
print(result1)
输出结果:

$ 规定数据从末尾开始取值
import re
txt="""张三 python工程师 8000
李四 java工程师 10000
王五五 前端工程师 12000"""
pattern1=r'.{5}$' # $任何字符{5}要满足5个任意字符(.)联在一起,从末尾开始取值
result1=re.findall(pattern1,txt,re.M)
print(result1)
输出结果:机械式取值

从末尾开始取数字\d取数字+出现的都取
import re
txt="""张三 python工程师 8000
李四 java工程师 10000
王五五 前端工程师 12000"""
pattern1=r'\d+$' # $从末尾开始取数字\d取数字+出现的都取
result1=re.findall(pattern1,txt,re.M)
print(result1)
输出结果:

*代表全部都取值,当未取到值时为空
import re
txt="""张三 python工程师 8000
李四 java工程师 10000
王五五 前端工程师 12000"""
pattern1=r'\d*$' # $从末尾开始取数字\d取数字+出现的都取
result1=re.findall(pattern1,txt,re.M)
print(result1)
输出结果:

import re
txt="""张三,销售总监,5000,3000
李四,销售经理,4000,2000
王五五,渠道经理,3500,1000"""
pattern1=r',\d+,' # 会取到,
result1=re.findall(pattern1,txt,re.M)
print(result1)
输出结果:

限制输出某一部分
import re
txt="""张三,销售总监,5000,3000
李四,销售经理,4000,2000
王五五,渠道经理,3500,1000"""
pattern1=r',(\d+),' # 不会取到,只输出分组中的内容
result1=re.findall(pattern1,txt,re.M)
print(result1)
输出结果:

import re
txt="""张三,销售总监,5000,3000
李四,销售经理,4000,2000
王五五,渠道经理,3500,1000"""
pattern1=r',(\d+),(\d+)' # 会取到,
result1=re.findall(pattern1,txt,re.M)
print(result1)
输出结果:输出一个列表

\w 匹配包括下划线的任何单词字符
手机号匹配(1)首先手机号第一位1开头(2)拟定第二位满足3 5 8
import re
phones='''
13800001111
13900004321
15112341234
14100001234
12900003333
1c200005678
'''
pattern1=r'1[3,5,8]\d{9}' # 会取到,
result1=re.findall(pattern1,phones)
print(result1)
输出结果:

匹配a-e A-E开头的英文单词与匹配不是a-e A-E开头的英文单词
import re
words='''love
apple
bus
study
actor
great
Air
Business
strange
python
java
english
China
'''
pattern1=r'^[a-eA-E].+' # 从头开始取因为单词是一个一个的
result1=re.findall(pattern1,words,re.M)
print(result1)
pattern2=r'^[^a-eA-E].+' # 从头开始取因为单词是一个一个的
result2=re.findall(pattern2,words,re.M)
print(result2)
输出结果:

匹配英文单词进行取值
import re
words='''love apple bus study actor great Air Business strange python java english China
'''
pattern1=r'[a-eA-E]\w+' # 从头开始取因为单词是一个一个的
result1=re.findall(pattern1,words,re.M)
print(result1)
输出结果:

如果一个单词或者一端需要匹配的文字,被切断行了,使用re.S进行匹配
import re
msg='''我到万门
大学学习Python
'''
pattern1='到.*学*'
result1=re.findall(pattern1,msg,re.S)
print(result1)
输出结果:

取完整一句话中的空格和回车用\s取
import re
words='''我是 来自 一个 万门 大学 的 对 P ython 感兴趣的
纯爷们 或 小姐姐'''
pattern1='\s+'
result1=re.findall(pattern1,words)
print(result1)
输出结果:

取完整一句话中的非空格和回车用\S取
import re
words='''我是 来自 一个 万门 大学 的 对 P ython 感兴趣的
纯爷们 或 小姐姐'''
pattern1='\S+'
result1=re.findall(pattern1,words)
print(result1)
newres=''.join(result1)
print(newres)
输出结果:

使用|作为或or 双多条件匹配,if and or
import re
words='''
北京程序员工资10000元/月
上海程序员工资12000块/月
深圳程序员工资9500圆/月'''
pattern1=r'\d+元|\d+块|\d+圆' # 使用|作为或or 双多条件匹配,if and or
result1=re.findall(pattern1,words)
print(result1)
pattern2=r'\d+[元,块,圆]'
result2=re.findall(pattern2,words)
print(result2)
输出结果:

贪婪模式<.*>和非贪婪模式<.*?>
import re
# -----正则 .* 的贪婪模式
# -----正则 .*? 非贪婪模式
# -----我们就拿一个简单的网页取值来说(爬虫的第二级数据获取)
html="<html><header><title>万门大学</title></header><body><h1>Hello world</h1></body></html>"
#-----1 用<>做定位
#-----2 用<.*>取里边的值
pattern1=r'<(.*)>' # 使用|作为或or 双多条件匹配,if and or
result1=re.findall(pattern1,html)
print(result1)
pattern2=r'<(.*?)>' # 使用|作为或or 双多条件匹配,if and or
result2=re.findall(pattern2,html)
print(result2)
输出结果:

import re
# -----正则 .* 的贪婪模式
# -----正则 .*? 非贪婪模式
# -----我们就拿一个简单的网页取值来说(爬虫的第二级数据获取)
html="""
<html>
<header>
<title>万门大学</title>
</header>
<body>
<h1>Hello world</h1>
</body>
</html>
"""
#-----1 用<>做定位
#-----2 用<.*>取里边的值
pattern1=r'<(.*)>' # 使用|作为或or 双多条件匹配,if and or
result1=re.findall(pattern1,html)
print(result1)
pattern2=r'<(.*?)>' # 使用|作为或or 双多条件匹配,if and or
result2=re.findall(pattern2,html)
print(result2)
输出结果:
match和简单split
import re
qq1='1234@qq.com 45532441@qq.com 4134abc234@qq.com a123324844@qq.com 15532441@qq.com 14532433@qq.cn'
print(qq1.split(" "))
#切割也使用正则表达式
qq2='1234@qq.com*45532441@qq.com/4134abc234@qq.com a123324844@qq.com&15532441@qq.com#14532433@qq.cn'
pattern=r'[*/&#]'
res=re.split(pattern,qq2)
print(res)
输出结果:

import re
mail=' aaa@qq.cn bb@wanmen.org ccc@cc.com'
# ----现在的目标是想用.作为一个“坐标”来取值,但是,又是一个正则通配符号
pattern=r'@.*?\.\w+'
# ---解释一下 @这个是起点坐标.*? 是一个惰性 看到 一组 @ .之间的就取
# ---接着 \.就是 实际上一个.是一个标准符号坐标,不是正则通配符,他就代表它自己
# ---\w+剩下的所有字符都通配,遇到 空格就停止
res=re.findall(pattern,mail)
print(res)
输出结果:

特殊情况,掐头去尾,锁定固定长度,使用开头结尾标示^ $
import re
patt1=r'^a[1,2]$'
res1=re.match(patt1,'a1')
res2=re.match(patt1,'a2')
res3=re.match(patt1,'a1111')
res4=re.match(patt1,'a2222')
print(res1)
print(res2)
print(res3)
print(res4)
输出结果:

手机号正则表达式匹配
import re
# 手机号规则
# 做正则的时候一定要先拆出来你要匹配的规则 一般前三位是一个规则
# 然后后边8位数字
# 当然位数只有能有数字
pattern1=r'^(13[0-9]|14[5|7]|15[0|1|2|3|4|5|6|7|8|9]|18[0|1|2|3|4|5|6|7|8|9])\d{8}$'
res=re.match(pattern1,'15683039101')
print(res)
print(bool(res))
if res:
print("找到了")
else:
print("没找到")
输出结果:

邮箱匹配
import re
# 手机号规则
# 做正则的时候一定要先拆出来你要匹配的规则 一般前三位是一个规则
# 然后后边8位数字
# 当然位数只有能有数字
pattern1=r'^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$'
res=re.match(pattern1,'_dhadj@asdf.com')
print(res)
print(bool(res))
if res:
print("找到了")
else:
print("没找到")
输出结果:
网页网站正则表达式匹配
import re
articles=[
"<li><a href='http://www.xiaole8.com/shangganwenzhang'>伤感文章</a></li>",
"<li><a href='http://www.xiaole8.com/aiqingwenzhang'>爱情文章</a></li>",
"<li><a href='http://www.xiaole8.com/ganrengushi'>感人故事</a></li>",
"<li><a href='http://www.xiaole8.com/qingganmeiwen'>情感美文</a></li>",
"<li><a href='http://www.xiaole8.com/lizhiwenzhang'>励志文章</a></li>",
"<li><a href='http://www.xiaole8.com/renshengzheli'>人生哲理</a></li>",
"<li><a href='http://www.xiaole8.com/gaoxiaowenzhang'>搞笑文章</a></li>",
"<li><a href='http://www.xiaole8.com/jingdianwenzhang'>经典文章</a></li>",
"<li><a href='http://www.xiaole8.com/qinqingwenzhang'>亲情文章</a></li>",
"<li><a href='http://www.xiaole8.com/youqingwenzhang'>友情文章</a></li>",
]
pattern=r"<li><a href='(.*?)'>(.*?)</a></li>"
output={}
for article in articles:
res=re.findall(pattern,article)
print(res[0][0])
output[res[0][1]]=res[0][0]
print(output)
输出结果:


浙公网安备 33010602011771号