1.正则表达式语法
from re import fullmatch
from re import match
正则表达式是用来匹配或者描述字符串的工具
用处:
a.判断输入的字符串是否是邮箱/手机号码。是否ip地址等 等
b.提取满足条件的字符串
c.字符串替换
python中通过re模块相应的方法来支持正则表达式的匹配、查找、替换等功能
match --> 匹配
fullmatch(正则表达式字符串, 字符串) --> 完全匹配,查看正则表达式和字符串是否完全匹配
正则表达式: 就是一个字符串,字符串中是正则表达式语法, r"正则表达式"
正则表达式中包含两个部分, 一个是正则语法对应的字符, 二个是普通字符
1. .匹配任意字符 --> 一个点只匹配一个任意字符
- 匹配一个长度是3的字符串, 第一个字符是a, 第二个字符是任意字符, 最后一个字符是b
re_str = r'a.b'
print(fullmatch(re_str, 'acb'))
- 匹配一个长度是4,第一个字符是a,第二个字符是b最后两个字符是任意字符的字符串
re_str1 = r'ab..'
print(fullmatch(re_str1, 'ab1a'))
2. \w --> 匹配字母数字下划线 一个\w匹配的是一个字符
- 匹配一个第一个字符是数字、字母或者下划线, 后面三个字符是任意字符的字符串
re_str2 = r'\w...'
print(fullmatch(re_str2, '_d +'))
3. \s --> 匹配任意空白字符, 所有能产生空白的字符
re_str4 = r'a\sb'
print(fullmatch(re_str4, 'a\tb'))
4. \d --> 匹配数字字符
re_str5 = r'\d\d\d'
print(fullmatch(re_str5, '555'))
5. \b --> 检测边界,一个\b不会去匹配一个字符,而是单纯的检测\b出现的位置是否是单词边界
- 单词边界: 字符串开始或者结尾,空格、换行、\t、逗号等等可以将两个单词隔开的字符都是单词边界
re_str6 = r'\d..\b'
print(fullmatch(re_str6, '4ad'))
re_str7 = r'abc\ba33' --> 没有字符串能匹配
re_str7 = r'abc/b/sa33' #--> 匹配一个字符串前三位是abc,第四位是空格,后三位是a33,并且要求c字符后面是单词边界
print(fullmatch(re_str7, 'abc\na33'))
6. ^ --> 检测是否是字符串开头
re_str8 = r'^\d\d\d' # 判断一个字符串是否是三个数字开头
print(fullmatch(re_str8, '333'))
7. $ --> 检测是否是字符串结尾
re_str9 = r'abc$'
print(fullmatch(re_str9, 'abc'))
8. \W --> 匹配非字母、数字下划线
re_str10 = r'\Wabc'
print(fullmatch(re_str10, '*abc'))
9. \S --> 匹配非空白字符
re_str11 = r'\S\d\d\d' # 匹配第一个是非空白字符,后面三个数字
print(fullmatch(re_str11, '+333'))
10. \D --> 匹配非数字字符
re_str12 = r'\D\s\w'
print(fullmatch(re_str12, 'e r'))
11. \B --> 检测非边界
re_str13 = r'abc\B5b'
print(fullmatch(re_str13, 'abc5b'))
12. [] --> 匹配中括号中出现的任意一个字符
- [字符集] --> 匹配一个字符,这字符是字符集中的任意一个字符
- [字符1-字符2] --> 匹配一个字符,这个字符是Unicode编码值在字符1到字符2中的任意字符要求字符1小于字符2
[\u0031-\u0039] --> 使用原始字符,匹配0~9的数字
[\u4E00-\u9fa5] --> 匹配所有的汉字
注意: -在中括号中,如果放在两个字符之间表示范围,表示减号就得放在字符前面或者后面
re_str14 = r'[abcd]aaa' # 匹配第一个字符是abcd中的任意单个字符,后面三个是aaa的字符串
print(fullmatch(re_str14, 'daaa'))
re_str15 = r'[1-4]\d\d\d' # 检测第一位字符串是1~4,后面三位是任意数字的字符串
print(fullmatch(re_str15, '2789'))
re_str16 = r'[\u0031-\u0039]aa'
print(fullmatch(re_str16, '8aa'))
re_str17 = r'[\u4E00-\u9fa5][\u4E00-\u9fa5][\u4E00-\u9fa5]'
print(fullmatch(re_str17, '哈哈哈'))
re_str18 = r'18208333774'
print(fullmatch(re_str18, '18208333774'))
# 匹配一个字符是字母数字下划线或者空白
re_str19 = r'[\w\s]'
print(fullmatch(re_str19, '_'))
13. [^] 匹配一个不在[]中的字符集中的任意字符,注意''只能放在中括号最前面
re_str20 = r'[^abc]...' # 匹配第一个字符不是abc任意一个,其他为任意字符的字符串
print(fullmatch(re_str20, 'd123'))
re_str21 = r'[^1-9]...' # 第一个字符不能是1-9
print(fullmatch(re_str21, '0123'))
2.正则表达式匹配次数的符号
from re import fullmatch
1. * --> 匹配0次或者多次,注意*前面必须要有个字符
str1 = r'\d*' # 匹配0位或者多位的数字字符串
print(fullmatch(str1, ''))
print(fullmatch(str1, '2132'))
用正则表达式来检测一个标识符是否符合要求: 数字字母下划线组成,数字不开头
str2 = r'[a-zA-Z_]\w*'
print(fullmatch(str2, 'a2sd'))
2. + --> 匹配一次或者多次,注意+前面必须要有字符
str3 = r'\d+abc' # 匹配前面一个或者多个数字,结尾abc的字符串
print(fullmatch(str3, '213abc'))
3. ? --> 匹配0次或者1次
str4 = r'a?123' # 匹配a123 123
# 练习: 写一个正则表达式匹配所有的整数(123, -2334, +9)
str5 = r'[+-]?[1-9]\d*'
print(fullmatch(str5, '+20213'))
4. {} --> 指定次数
{n} --> 匹配n次
{m,n} --> 匹配m~n次
{m,} --> 至少匹配m次
{,n} --> 最多匹配n次
str6 = r'\d{3}' # 匹配数字三次
print(fullmatch(str6, '123'))
str7 = r'\d{3,}'
print(fullmatch(str7, '123'))
str8 = r'[a-z]{2,5}'
print(fullmatch(str8, 'daksk'))
# 判断密码是否符合要求: 密码是由数字和字母组成,并且位数是6~16位
str_pw = r'[0-9a-zA-Z]{6,16}'
print(fullmatch(str_pw, 'sandkjhi12'))
3.分支和分组
from re import fullmatch
import re
1. | --> 分支
- 条件1|条件2 --> 先用条件1去匹配,如果匹配成功,就结束,如果条件1匹配失败,用条件2去匹配
注意: 如果条件1匹配成功就不会用条件2再去匹配
re_str = r'[a-z]{3}|[A-Z]{3}' # 会把|的前面和后面作为一个整体条件
print(fullmatch(re_str, 'abc'), fullmatch(re_str, 'ABC'))
re_str = r'abc|d' # |前面和后面作为整体条件,要么abc要么d
print(fullmatch(re_str, "abc"), fullmatch(re_str, 'd'))
2. () --> 分组
a.将括号中的内容作为一个整体进行操作 --> 'abc' + W|H|Y
b.捕获 --> 使用带括号的正则表达式匹配成功后只获取()中的内容
c.重复 --> 在正则表达式中可以通过\数字来重复前面()中匹配到的结果,数字代表的是第几个括号
re_str = r'abc(W|H|Y)'
print(fullmatch(re_str, 'abcW'))
# 需要一个数字加一个字母出现三个的字符串
# 组合
re_str = r'(\d[a-zA-Z]){3}'
print(fullmatch(re_str, '1a2b3c'))
# 捕获
re_str = r'\d{3}abc'
print(fullmatch(re_str, "333abc")) # 将满足正则表达式的式子返回列表
print(re.findall(re_str, '213abc233abc'))
re_str = r'(\d{3})abc' # 捕获时只取括号内的内容
print(re.findall(re_str, '213abc233abc'))
# 重复
re_str = r'([a-z]{3})-(\d{2})\1\2'
print(re.fullmatch(re_str, 'ccc-22ccc22'))
3.正则表达式转义字符
正则表达式可以通过在特殊符号前加\来使特殊符号没有功能 . + * ? ^
. --> 任意字符 . --> 字符.
- --> 匹配一次或者多次 + --> 字符+
注意: 在中括号中,特殊字符可以不用\转义,-号除外,\在哪儿都需要转义
()在外边需要转义,放在中括号内不需要转义
re_str = r'\d{2}\.\d{2}'
print(fullmatch(re_str, '12.22'))
re_str = r'\d\+\d'
print(fullmatch(re_str, '3+7'))
4.re模块中的函数
import re
1. compile
compile(正则表达式字符串) --> 将正则表达式字符串转化成正则表达式对象,先转化为对象,之后调用fullmatch只需要传1个参数,直接传字符串
re_object = re.compile(r'\d+')
print(re_object)
print(re_object.fullmatch("21312"))
2. fullmatch/match
fullmatch(正则表达式字符串,需要去匹配的字符串) --> 用正则表达式去完全匹配字符串,返回匹配对象
match(正则表达式字符串, 字符串) --> 匹配字符串开头,看字符串开头是否满足要求,返回匹配对象或者None
result = re.fullmatch(r'\d[a-zA-Z]+', '2jk')
print(result, type(result))
1.span() --> 获取的是匹配成功的开始下标和结束下标(取不到的)
print(result.span())
print(result.start()) # 获取匹配到的开始下标
print(result.end()) # 获取匹配到的结束下标后的下标
print('=============')
2.group(下标) --> 获取匹配的结果,下标默认值为0
group() --> 获取正则表达式完全匹配的结果
group() --> 有下标的时候,获取正则表达式中第下标个分组匹配到的结果
print(result.group())
3.search(正则表达式, 字符串) --> 查找字符串中满足正则表达式的第一个字符串,返回值是匹配对象或者None
result = re.search(r'(\d)[a-zA-Z]+', 'uakd3abcd_sjk3k')
print(result)
print(result.group(1))
# 练习: 用search匹配出一个字符串中所有的数字字符串
str1 = "ajkd34dajsk89sajdk23dska9akd567"
re_str = r'\d+'
result = re.search(re_str, str1)
while result:
print(result)
str1 = str1[result.end():]
result = re.search(re_str, str1)
4.string --> 获取被匹配的原字符串
5.findall
findall(正则表达式,字符串) --> 获取字符串中满足正则表达式所有的子串,返回结果位一个列表
注意: 如果正则表达式中有分组,取值的时候只取分组中匹配到的结果
如果有多个分组,会讲每个分组匹配到的结果作为一个元组的元素,将元组变为列表的元素
re_str = r'(\d+)k([a-d]+)'
str1 = 'abc34kmasmd8923kabc0kasdk89kaa'
result = re.findall(re_str, str1)
print(result) # [('8923', 'abc'), ('0', 'a'), ('89', 'aa')]
5.finditer
finditer(正则表达式,字符串) --> 查找所有满足正则表达式条件的子串,以迭代器返回,并且迭代器中的元素是匹配对象
re_str = r'\d+'
str1 = 'abc34kmasmd8923kabc0kasdk89kaa'
result = re.finditer(re_str, str1)
print(result)
for i in result:
print(i)
6.split
split(正则表达式,字符串) --> 把字符串按照满足正则表达式条件的子串进行分割
str1 = 'abs-d1k+smd3fh4+fcj59aj-d22'
re_str = r'[+-]'
result = re.split(re_str, str1)
print(result)
7.sub
sub(正则表达式,被替换字符串,字符串) --> 将字符串中满足正则表达式条件的子串替换成被替换的字符串
re_str = r'\d+'
str1 = 'asd55f5gh22j1sad3fj4'
rep = '*'
result = re.sub(re_str, rep, str1)
print(result)
str1 = '智 障,你在干嘛?'
result = re.sub(r'傻\s*叉|逼\s*|fuck|妈\s*的|智\s*障', "*", str1)
print(result)
5.歌词解析
需求: 播放指定歌曲的时候,给一个时间,能够把这首歌对应这个时间的词返回,面向对象: 找一个类,让它拥有解析歌词的功能
class Lyrics:
"""歌词类"""
def __init__(self, time='', word=''):
self._time = time
self.word = word
@property
def time(self):
return self._time
@time.setter
def time(self, value):
fen = float(value[1:3])
m = float(value[4:])
self._time = fen*60 + m
def __gt__(self, other):
return self._time > other._time
def __repr__(self):
return str(self.__dict__)
class LyricsAnalysis:
"""
歌词解析类
name对应的是解析的歌名
"""
def __init__(self, name):
self.__name = name
self.__all_lyric = [] # 保存当前歌名解析出来的所有词
# 分离歌词和时间
def __split_t_ric(self, line):
# 时间 <-> 歌词
line_list = line.split(']')
# print(line_list)
# 获取每一行的词
word = line_list[-1]
# 遍历获取每一行的时间
for time in line_list[:-1]:
# 根据时间和歌词创建歌词对象
ly_obj = Lyrics(word=word)
ly_obj.time = time
self.__all_lyric.append(ly_obj)
# 根据时间获取歌词
def get_lyrics(self, time: int):
"""
读文件内容
解析文件
找到时间
将时间返回
"""
# 判断之前是否已经解析过
if self.__all_lyric:
# 解析过根据时间取值
for item in self.__all_lyric:
if item.time < time:
return item.word
try:
with open('./files/' + self.__name + '.txt', 'r', encoding='utf-8') as f:
line = f.readline()
while line:
# print(line)
self.__split_t_ric(line)
line = f.readline()
# 排序
self.__all_lyric.sort(reverse=True)
# 根据时间取值
for item in self.__all_lyric:
if item.time < time:
return item.word
except FileNotFoundError:
print("没有相应的歌词")
ly_lan = LyricsAnalysis('蓝莲花')
print(ly_lan.get_lyrics(10))