01 什么是正则
1.正则的作用
正则表达式是一种可以让复杂的字符串变得简单的工具
写正则表达式的时候就是用正则符号来描述字符串规则
先加载re模块
import re
例1:判断一个字符串是否是一个合法的电话号码
tel = '18613213264'
# 方法1不用正则
if len(tel) == 11:
if tel[0] == '1':
if tel[1] in '3456789':
if tel[2: ].isdigit():
print( '合法')
else:
print('不合法')
else:
print( '不合法')
else:
print( '不合法')
else:
print('不合法')
# 方法2 利用正则
result = re.fullmatch(r'1[3-9]\d{9}', tel)
if result:
print('合法')
else:
print('不合法')
例2:提取字符串中所有的数字子串,并且求和
print('----------------------------------------')
str1 = '睡觉89jss=3.45-换手23=抗生素820=8'
result = re.findall(r'\d+\.?\d*', str1)
print(sum([float(x) for x in result]))
02 正则语法
1.re模块 - 提供了python中所有与正则相关的函数
from re import fullmatch, findall, search
fullmatch(正则表达式, 字符串) - 判断整个字符串是否满足正则表达式所描述的规则
findall(正则表达式, 字符串) - 提取字符串中所有满足正则表达式的子串
search(正则表达式, 字符串) - 匹配字符串中第一个满足正则表达式的子串
Attention:Python中表示一个正则表达式一般使用r字符串
2.正则符号
============== 第一类 匹配类符号 ==============
2.1 普通符号 - 在正则表达式中表符号本身的符号
import requests
print('第一类 匹配类符号----------------------------------------')
result = fullmatch(r'abc', 'abc')
print(result) # 匹配对象:<re.Match object; span=(0, 3), match='abc'>
2.2 . - 匹配任意一个字符
result = fullmatch(r'.bc', '好bc')
print(result)
2.3 /d - 匹配任意一个数字字符
result = fullmatch(r'\d\dabc', '67abc')
print(result)
2.4 /s - 匹配任意一个空白字符
空白字符:空格(’ ‘)、换行(’\n’)、水平制表符(‘\t’)
result = fullmatch(r'123\sabc', '123 abc')
print(result)
result = fullmatch(r'\d\d\s\d', '13\n5')
print(result)
2.5 \w - 匹配任意一个字母、数字、下划线或者中文
result = fullmatch(r'abc\w123', 'abc和123')
print(result)
2.6 \D、\S、\W - 分别与\d、\s、\w的功能相反
result = fullmatch(r'abc\D123', 'abc6123')
print(result) # 不匹配,返None
2.7 [字符集] - 匹配在字符集中的任意一个字符
[abc] - 匹配a或者b或者c
[abc\d] - 匹配a或者b或者c或者任意数字
[1-5] - 匹配1-5中任意一个字符
[a-z] - 匹配任意一个小写字母
[A-Z] - 匹配任意一个大写字母
[a-zA-Z] - 匹配任意一个字母
[a-zA-Z\d] - 匹配任意一个字母或数字
[a-z=%] - 匹配任意一个小写字母 + ‘=’ + ‘%’
[\u4e00-\u9fa5] - 匹配任意一个中文字
result = fullmatch(r'abc[M9你\\d]123', rf'abc9123')
print(result)
2.8 [^字符集] - 匹配不在字符集中的任意一个字符
result = fullmatch(r'abc[^MN]123', 'abc.123')
print(result)
============== 第二类 匹配次数符号 ==============
必须先写匹配类符号再跟匹配次数
2.9 * - 任意次数(0次或1次或多次)
a* - a出现任意多次
\d* - 任意多个任意数字
[abc]* - 任意多个abc
print('第二类 匹配次数符号----------------------------------------')
result = fullmatch(r'1a*2', '1aaaaaaaaaaaa2')
print(result)
result = fullmatch(r'M[3-9]*N', 'M569865N')
print(result)
2.10 + - 一次或多次(至少1次)
result = fullmatch(r'Aa+C', 'AaaC')
print(result)
2.11 ? - 0次或1次
result = fullmatch(r'1a?2', '1aa2')
print(result) # 不匹配,返None
2.12 匹配任意次数的写法
{N} - N次
{M,N} - M到N次
{M,} - 至少M次
{,N} - 最多N次
result = fullmatch(r'1a{3,6}2', '1aaa2')
print(result)
练习1:写一个写一个正则表达式,可以匹配任意一个除了0的整数。
233、+234、-7283
print('练习1----------------------------------------')
result = fullmatch(r'[+-]?[1-9]\\d*', '3330')
print(result)
2.13 ★贪婪和非贪婪模式
在匹配次数不确定的时候,如果有多种次数都可以匹配成功,贪婪取最多的次数,非贪婪取最少的>次数。(默认是贪婪模式)
贪婪模式:+、?、、{M,N}、{M,}、{,N}
非贪婪模式:+?、??、?、{M,N}?、{M,}?、{,N}?
# 贪婪模式
result = search(r'a.+b', '哈哈哈哈ahkmb是石双德bxybs5151f5')
print(result) # <re.Match object; span=(4, 17), match='ahkmb是石双德bxyb'>
# 非贪婪模式
result = search(r'a.+?b', '哈哈哈哈ahkmb是石双德bxybs5151f5')
print(result) # <re.Match object; span=(4, 9), match='ahkmb'>
练习2:使用正则提取top250中每个电影的详情页地址
print('练习2----------------------------------------')
# import requests
# from re import findall
# header = {
# 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.95 Safari/537.36'
# }
# response = requests.get('https://movie.douban.com/top250?start=0&filter=', headers=header)
# result = findall('<a href="(https://movie.douban.com/subject/\d*/)">', response.text)
# print(result)
============== 第三类 ★分组和分支 ==============
2.14 分组 - ()
正则表达式中可以用()将部分内容括起来表示一个整体。括号括起来的部分就是一个分组。
a.整体操作的时候需要分组
b.重复匹配:正则中可以通过\M来重复它前面第M个分组匹配的结果
c.捕获:提取分组匹配到的结果(自动捕获(findall)、手动捕获(其余正则函数))
例1:‘23M’、‘89K10L’、‘09H23P90Q33W’、 …
result = fullmatch(r'(\d\d[A-Z])+', '23M06N58M84V')
print(result)
例2:‘23H23’、‘90K90’、‘78N78’、‘10U10’
result = fullmatch(r'(\d\d)[A-Z]\1', '23M23')
print(result)
result = fullmatch(r'(\d{3})([a-z]{2})=\2\1{2}\2', '231nm=nm231231nm')
print(result)
★自动捕获(findall)函数在正则表达式中有分组的时候,会自动提取正则匹配结果中分组匹配到的内容
message = '极少数234,ckokqwopd5856.959==w积分12ndfk2=e5fv51-511'
result = findall(r'[\u4e00-\u9fa5](\d+)', message)
print(result)
手动捕获(其余正则函数如:search)
匹配对象.group(N) - 获取匹配结果中指定分组匹配到的内容
massage = '我是小明,今年23岁,身高180cm,体重70kg'
result = search(r'身高(\d+)cm,体重(\d+)kg', massage)
print(result) # 匹配对象:<re.Match object; span=(11, 25), match='身高180cm,体重70kg'>
print(result.group()) # 身高180cm,体重70kg
print(```
#### 2.15 分支 - |
>正则1|正则2|正则3|... - 先用正则1进行匹配,若正则1不成功则用正则2进行匹配...若都匹配不成>功则返回None
```python
result = fullmatch(r'\d{3}|[a-z]{2}', 'mn')
print(result)
'abc34’或’abcKJ
result = fullmatch(r'abc(\d{2}|[A-Z]{2})', 'abcKJ')
print(result)
============== 第四类 ★转义符号 ==============
2.16 转义符号:在本身具有特殊功能或特殊意义的符号前加 \ ,让特殊符号变普通字符
print('第四类 ★转义符号----------------------------------------')
# 匹整数部分和小数部分都是两位数的小数
result = fullmatch(r'\d\d\.\d\d', '45.36')
print(result)
result = fullmatch(r'\d\+\d', '4+3')
print(result)
# '(amd)'
result = fullmatch(r'\([a-z]{3}\)', '(amd)')
print(result) # <re.Match object; span=(0, 5), match='(amd)'>
Attention:单独存在有特殊意义的符号,在[]中它的功能会自动消失
03 re模块补充
from re import fullmatch, findall, search, match, finditer, split, sub, subn, escape
1)fullmatch(正则表达式, 字符串) - 用整个字符串和正则,匹配成功返回匹配对象,匹配失败返回>None。(如匹配手机号、邮箱、IP地址等)
2)findall(正则表达式, 字符串) - 获取字符串中所有满足正则的子串,默认返回一个列表,列表中>的元素是所有匹配到的子串。(存在自动捕获现象)
3)search(正则表达式, 字符串) - 匹配字符串中第一个满足正则表达式的子串。若匹配失败则返>None
4)split(正则表达式, 字符串, [N]) - 将字符串中所有满足正则的子串作为切割点进行切割,[N]是>用前N个来进行切割
5)sub(正则表达式, 字符串1, 字符串2) - 将字符串2中所有满足正则的子串都替换成字符串1
6)sub(正则表达式, 字符串1, 字符串2, N) - 将字符串2中前N个满足正则表达式的子串替换成字符>串1
7)finditer(正则表达式, 字符串) - 获取字符串中所有满足正则的子串,返回一个迭代器,迭代器>中的元素是匹配对象
8)match(正则表达式, 字符串) - 匹配字符串开头
# 用字符串的切割函数来切割
str1 = '技术7晋级赛7sks7就开始看'
print(str1.split('7'))
# 用正则的切割模块来切割
str2 = '技术22晋级赛7sks5就开始8看'
print(split(r'\d+', str2, 2)) # ['技术', '晋级赛', 'sks5就开始8看']
str3 = '技术22晋级赛7sks5就开始8看'
print(sub(r'\d+', '+', str3)) # 技术+晋级赛+sks+就开始+看
message = '妈的,sb,SB,都打起来了你还在打野!草!fuck'
print(sub(r'(?i)妈的|sb|草|操|艹|f\s*u\s*c\s*k', '*', message))
str4 = '技术22晋级赛7sks5就开始8看'
result = finditer(r'\d+', str4)
print(list(result))
# print(list(result)[1].group())
print(fullmatch(r'\d{3}', '234'))
print(match(r'\d{3}', '234卡咖啡'))
补充1:匹配时忽略大小写
print(fullmatch(r'abc', 'abc')) # 一般情况
print(fullmatch(r'(?i)abc', 'AbC')) # 忽略大小写
补充2:
单行匹配:(?s)
print(fullmatch(r'(?s)abc.123', 'abc\n123')) # <re.Match object; span=(0, 7), match='abc\n123'>
多行匹配(默认):. - 不能和换行符进行匹配
print(fullmatch(r'abc.123', 'abc\n123')) # None
msg = """
'name:"jshf2-
2ss技术"'
"""
result =findall(r'(?s)name:"(.+)"', msg)
print(result)
04 正则表达式作业
一、不定项选择题
-
能够完全匹配字符串"(010)-62661617"和字符串"01062661617"的正则表达式包括( A B D)
A.
r"\(?\d{3}\)?-?\d{8}"
B.r"[0-9()-]+"
C.r"[0-9(-)]*\d*"
D.r"[(]?\d*[)-]*\d*"
-
能够完全匹配字符串"back"和"back-end"的正则表达式包括( A B C )
A.r'\w{4}-\w{3}|\w{4}'
B.r'\w{4}|\w{4}-\w{3}'
C.r'\S+-\S+|\S+'
D.r'\w*\b-\b\w*|\w*'
-
能够完全匹配字符串"go go"和"kitty kitty",但不能完全匹配“go kitty”的正则表达式包括(D)
A.r'\b(\w+)\b\s+\1\b'
B.r'\w{2,5}\s*\1'
C.r'(\S+) \s+\1'
D.r'(\S{2,5})\s{1,}\1'
-
能够在字符串中匹配"aab",而不能匹配"aaab"和"aaaab"的正则表达式包括( B)
A.r"a*?b"
B.r"a{,2}b"
C.r"aa??b"
D.r"aaa??b"
二、编程题
1.用户名匹配
要求: 1.用户名只能包含数字 字母 下划线
2.不能以数字开头
3.⻓度在 6 到 16 位范围内
username = 'dwdw_wdf'
result = fullmatch(r'\D[\dA-Za-z_]{5,15}', username)
print(result)
-
密码匹配
要求: 1.不能包含!@#¥%^&*这些特殊符号 2.必须以字母开头 3.⻓度在 6 到 12 位范围内
password = 'dwdw_wdf'
result = fullmatch(r'[A-Za-z][^!@#¥%^&*]{5,11}', password)
print(result)
- ipv4 格式的 ip 地址匹配
提示: IP地址的范围是 0.0.0.0 - 255.255.255.255
ipv4 = '155.255.8.0'
result = fullmatch(r'([0-9]|[1-5][1-5]|[1-2]?[1-5][1-5])\.([0-9]|[1-5][1-5]|[1-2]?[1-5][1-5])\.([0-9]|[1-5][1-5]|[1-2]?[1-5][1-5])\.([0-9]|[1-5][1-5]|[1-2]?[1-5][1-5])', ipv4)
print(result)
- 提取用户输入数据中的数值 (数值包括正负数 还包括整数和小数在内) 并求和
例如:“-3.14good87nice19bye” =====> -3.14 + 87 + 19 = 102.86
str4 = '-3.14good87nice19bye'
result = eval('+'.join(findall(r'[+-]?\d+\.?\d+', str4)))
print(result)
- 验证输入的内容只能是汉字
str5 = '哈哈哈哈'
result = fullmatch(r'[\u4e00-\u9fa5]*', str5)
print(result)
- 匹配整数或者小数(包括正数和负数)
str6 = '-12.3'
result = fullmatch(r'[+-]?\d+\.?\d+', str6)
print(result)
-
验证输入用户名和QQ号是否有效并给出对应的提示信息
要求:
用户名必须由字母、数字或下划线构成且长度在6~20个字符之间
QQ号是5~12的数字且首位不能为0
username = input('用户名:')
qq = input('QQ:')
result1 = fullmatch(r'[A-Za-z\d_]{6,20}', username)
result2 = fullmatch(r'[1-9]\d{4,11}', qq)
print(result1)
print(result2)
-
拆分长字符串:将一首诗的中的每一句话分别取出来
poem = '窗前明月光,疑是地上霜。举头望明月,低头思故乡。'
poem = '窗前明月光,疑是地上霜。举头望明月,低头思故乡。'
result = findall(r'[\u4e00-\u9fa5]+[,。]?', poem)
print(result)