熟悉正则表达式
# 正则表达式是对字符串操作的一种逻辑公式,使用事先定义好的一些'特定字符'及特定字符的'组合',组成一个'规则字符串' # 这个'规则字符串'表示对字符串(普通字符和特殊字符)操作的一种逻辑公式. # 作用: 1-给定字符串是否匹配正则表达式的过滤逻辑 2-通过正则表达式从字符串中获取我们想要的特定部分 # 特点: 1-灵活,逻辑性和功能性强 2-用简单的方式达到字符串的复杂控制 # 使用场景: 判断手机号是否符合 判断填写的邮箱是否符合格式 # re模块: 提供正则相关的操作
# 使用试例
msg1 = '杰伦德华赵本山'
# re.compile(pattern) pattern正则表达式 编译一个正则表达式模式,返回一个pattern(正则表达式模式)对象
pattern1 = re.compile('赵本山')
# pattern.match(AnyStr) -> Match[AnyStr] | None (match:使匹配)
print(pattern1.match(msg1)) # None match()方法会从前往后进行匹配,如果不同则直接返回None
# 交换一下msg中要匹配的str的位置,就会改变输出结果
msg2 = '赵本山杰伦德华'
pattern2 = re.compile('赵本山')
print(pattern2.match(msg2)) # <re.Match object; span=(0, 3), match='赵本山'> 匹配成功返回match对象
# 使用re模块内封装的match()方法
# re.match(pattern, String):尝试在字符串开头匹配正则表达式,匹配到则返回Match对象,匹配不到则返回None
print(re.match('赵本山', msg1)) # None
print(re.match('赵本山', msg2)) # <re.Match object; span=(0, 3), match='赵本山'>
# re.search(pattern, String):扫描字符串,如果找到与正则表达式匹配则返回Match对象,如果没有找到则返回None。
print(re.search('赵本山', msg1)) # <re.Match object; span=(4, 7), match='赵本山'>
print(re.search('赵本山', msg2)) # <re.Match object; span=(0, 3), match='赵本山'>
# 我们也可以接收这个Match对象,通过这个对象来操作里面的内容
search_match = re.search('赵本山', msg1)
print(search_match.span()) # 返回与其相匹配的字符串位置 (4, 7)
print(search_match.group()) # 返回与其相匹配的字符串内容 赵本山
正则表达式的基本操作
# 在熟悉了正则表达式的使用场景与用法,我们接下来就需要更灵活的去学习它.
'''
# '.': 用于匹配除换行符外(\n)的所有字符(写在正则表达式中表示取反)
# '^': 用于匹配字符串的开始,即首行 如果没有^则只从符合匹配条件的字符开始匹配
# '$': 用于匹配到字符串的结尾,(末尾如果有换行符\n,就匹配\n前面的那个字符),即行尾 如果没有$则只匹配到符合需求的就不会匹配后面的字符
# 定义正则表达式验证次数的符号:
# '*': 用于将前面的正则模式匹配0次或多次(贪婪模式:尽可能多的匹配) >=0
# '+': 用于将前面的正则模式匹配一次或多次(贪婪模式:尽可能多的匹配) >=1
# '?': 用于将前面的正则模式匹配0次或1次(贪婪模式:尽可能多的匹配) [0, 1]次
# '*?' '+?' '??': 表示上面三种字符的非贪婪模式:尽可能少的匹配
# '{m}': 用于验证将前面的正则模式匹配m次
# '{m,}': 用于验证将前面的正则模式匹配m次或多次 >=m
# '{m,n}': 用于将前面正则模式匹配m次到n次(贪婪模式),最小匹配m次,最大匹配n次
# '{m,n}?': 用于将前面正则模式匹配m次到n次(非贪婪模式),最小匹配m次,最大匹配n次
'''
# 正则表达式中的符号: # '[]': 用于标识一组字符,如果^是第一个字符,则表示的是一个补集.比如[0-9]表示所有数字,[^0-9]表示除数字外的字符
# 提取到符合 - '字母,数字,字母' - 这种规则的字符串出来
msg3 = 'a2fh23gw3eq8asf1h'
search_match = re.search('[a-z][0-9][a-z]', msg3)
print(search_match.group()) # a2f re.search()方法特点:只要找到第一个匹配正则的字符串,就停止匹配.(只能找到第一个符合正则的字符串)
# 如果需要找到所有符合条件的方法则使用re.findall(pattern, string)方法 # 将字符串中所有匹配项以列表形式返回
re_findall1 = re.findall('[a-z][0-9][a-z]', msg3)
print(re_findall1) # ['a2f', 'w3e', 'q8a', 'f1h']
# 如果不管字母中间有几个数字的这种字符串都找到需要怎么办呢?
re_findall2 = re.findall('[a-z][0-9]+[a-z]', msg3)
print(re_findall2) # 使用符号便可以完成我们的需求了 ['a2f', 'h23g', 'w3e', 'q8a', 'f1h']
# 通过几个例子来了解上面符号的用法:
# QQ号码验证:5-11位,首位不能为0 '^[1-9][0-9]{4,10}$' 经测试符合条件
QQ_num1 = '12345'
QQ_num2 = '1234'
QQ_num3 = '12345678901'
QQ_num4 = '123456789012'
result1 = re.match('^[1-9][0-9]{4,10}$', QQ_num1)
result2 = re.match('^[1-9][0-9]{4,10}$', QQ_num2)
result3 = re.match('^[1-9][0-9]{4,10}$', QQ_num3)
result4 = re.match('^[1-9][0-9]{4,10}$', QQ_num4)
print(result1) # <re.Match object; span=(0, 5), match='12345'>
print(result2) # None
print(result3) # <re.Match object; span=(0, 10), match='12345678901'>
print(result4) # None
# 用户名可以是字母或数字,不能以数字开头,用户名必须6位以上 [0-9a-zA-Z]
username1 = '00admin' # 数字开头
username2 = 'admin&*' # 加特殊符号
username3 = 'admin' # 正常用户名
print(re.match('[a-zA-Z][0-9a-zA-Z]', username1)) # None
print(re.match('[a-zA-Z][0-9a-zA-Z]', username2)) # <re.Match object; span=(0, 2), match='ad'>
print(re.match('[a-zA-Z][0-9a-zA-Z]', username3)) # <re.Match object; span=(0, 2), match='ad'>
# 如果我们不使用$符号的话,可以看到不符合规则的username2也匹配成功了,这时候我们在末尾加上$测试
print(re.match('[a-zA-Z][0-9a-zA-Z]$', username2)) # None 当加上$表示要一直匹配到字符串结尾,这样加上特殊符号的username2就不符合条件了
# 由于match()函数是从头开始匹配字符串的,所以我们不需要使用^符号,那么我们使用search函数测试一些username1的效果是什么呢?
print(re.search('[a-zA-Z][0-9a-zA-Z]', username1)) # <re.Match object; span=(2, 4), match='ad'> 数字开头也显示匹配成功
# 原因是没有^符号,search函数只要在字符串中匹配到符合正则的字符就会返回,所以我们加上^符号,要求从头匹配.
print(re.search('^[a-zA-Z][0-9a-zA-Z]', username1)) # None
# 通过上面两个例子我们应该理解了符号'^'和'$'的使用方法了: '^...$'表示从头到尾,拿整个字符串进行匹配!
# 那有没有什么能代替上面比较麻烦的书写呢?还真有:
'''
# \A: 表示从字符串的开始处匹配
# \Z: 表示从字符串的结束处匹配,如果存在换行,只匹配到换行前的结束字符串
# \b: 匹配一个单词边界,指单词和空格间的位置,例:'py\b'可以匹配'python'中的py,但不能匹配'openpyxxm'中的py
# \B: 匹配一个非单词边界,'py\B'可以匹配'openpyxxm'中的py,但不能匹配'python'中的py
# \d: 匹配任意数字,等价于[0-9]
# \D: 匹配任意非数字,等价于[^\d]
# \s: 匹配任意空白字符,等价于[\t\n\r\f]
# \S: 匹配任意非空白字符,等价于[^\s]
# \w: 匹配任意字母数字及下划线,等价于[0-9a-zA-Z_]
# \W: 匹配任意非字母数字及下划线,等价于[^\w]
# \\: 匹配反斜杠'\'
'''
# 那使用上面学到的重新写一个正则表达式看看效果 # 用户名符合字母数字下划线,不能以数字开头且用户名长度大于6: # 如果要使用整个字符串进行比较:由于match是从头开始的,所以只需要在末尾加$,search函数的话需要开头加^末尾加$
username4 = '00admin'
username5 = 'admin00'
print(re.match('[a-zA-Z]\w{5,}$', username4)) # None
print(re.match('[a-zA-Z]\w{5,}$', username5)) # <re.Match object; span=(0, 7), match='admin00'>
# 从一列字符串中找到.py文件:
str1 = 'aa.py bb.py cc.py apy.txt'
print(re.findall(r'py\b', str1)) # ['py', 'py', 'py', 'py'] 需要加上文件名
print(re.findall(r'\w\.py\b', str1)) # ['a.py', 'b.py', 'c.py'] 文件全名没匹配到
print(re.findall(r'\w*\.py\b', str1)) # ['aa.py', 'bb.py', 'cc.py'] 匹配成功
# 手机号码验证:
phone_num = '15233779988'
print(re.match(r'1[35789]\d{9}$', phone_num)) # <re.Match object; span=(0, 11), match='15233779988'>
正则表达式的分组
# 分组
'''
'|': 表示或者功能
'[adc]': 表示元素范围内单个的或者(a or b or c)
'(word1 | word2)': 表示整体范围内的或者(word1 or word2) 可以通过group(第几组)方法得到内容
'''
# 验证输入的邮箱格式 @163.com @qq.com @126.com
email_num1 = 'otto666@qq.com'
email_num2 = '666otto@163.com'
email_num3 = '66otto6@126.com'
print(re.match(r'\w{6,20}@(163|QQ|qq|126)\.(com|cn)$',
email_num1)) # <re.Match object; span=(0, 14), match='otto666@qq.com'>
print(re.match(r'\w{6,20}@(163|QQ|qq|126)\.(com|cn)$',
email_num2)) # <re.Match object; span=(0, 15), match='666otto@163.com'>
print(re.match(r'\w{6,20}@(163|QQ|qq|126)\.(com|cn)$',
email_num3)) # <re.Match object; span=(0, 15), match='66otto6@126.com'>
# 不以7结尾的手机号码
phone1 = '15233448877'
phone2 = '15233448888'
print(re.match(r'1\d{9}[1-689]$', phone1)) # None
print(re.match(r'1\d{9}[1-689]$', phone2)) # <re.Match object; span=(0, 11), match='15233448888'>
# match.group(): group方法可以获得不同组的信息 # 通过数字分组引用: # 将电话的区号和号码分别提取出来
phone3 = '010-12644448888'
re_match = re.match(r'(\d{3}|\d{4})-(\d{8,12})$', phone3)
print(re_match) # <re.Match object; span=(0, 15), match='010-12644448888'>
print(re_match.group()) # 010-12644448888
# ()表示分组,group(1)表示提取出第一组的内容
print(re_match.group(1)) # 010
print(re_match.group(2)) # 12644448888
# 从标签页中提取出信息 '.'表示所有字符 </1>表示匹配第一组的内容 如第一组内容位<html>则<1> = </html>
msg1 = '<h1>hello world</h1>'
re_match1 = re.match(r'<([0-9a-zA-Z]+)>(.+)</\1>$', msg1)
print(re_match1) # <re.Match object; span=(0, 20), match='<h1>hello world</h1>'>
print(re_match1.group()) # <h1>hello world</h1>
print(re_match1.group(1)) # h1
print(re_match1.group(2)) # hello world
msg2 = '<h1>hello world</h2>'
re_match2 = re.match(r'<([0-9a-zA-Z]+)>(.+)</\1>$', msg2)
print(re_match2) # None 因为</\1>的判定前后标签不一致,匹配不成功返回None
msg3 = '<h1><h2>hello world</h2></h1>'
re_match3 = re.match(r'<([0-9a-zA-Z]+)>(.+)</\1>$', msg3)
print(re_match3)
print(re_match3.group(2)) # <h2>hello world</h2>
# 如果是多个嵌套的标签体,我们怎么得到中间的信息呢? # 方法是我们也多嵌套一层正则表达式
re_match3 = re.match(r'<([0-9a-zA-Z]+)><([0-9a-zA-Z]+)>(.+)</\2></\1>$', msg3)
print(re_match3.group(1)) # h1
print(re_match3.group(2)) # h2
print(re_match3.group(3)) # hello world 成功拿到!
# 但当上面嵌套过于复杂时,很容易出现看串的情况,这里需要怎么优化一下呢? # 起名的方式解决: (?P<name>正则) (?P=name)
msg4 = '<h1><h2>hello world</h2></h1>'
re_match4 = re.match(r'<(?P<name1>[0-9a-zA-Z]+)><(?P<name2>[0-9a-zA-Z]+)>(.+)</(?P=name2)></(?P=name1)>', msg4)
print(re_match4) # <re.Match object; span=(0, 29), match='<h1><h2>hello world</h2></h1>'>
print(re_match4.group(3)) # hello world
# 其余re方法
# re.sub(正则表达式, 新内容, string):将正则表达式匹配到的内容替换为新内容
re_sub1 = re.sub(r'\d+', '99', '数学:59 英语:59')
print(re_sub1) # 替换结果: 数学:99 英语:99
# 新内容部分也可以放函数进行运算
def numplus(temp):
# temp.group()相当于匹配正则取出的结果
num = temp.group()
num1 = int(num)
num1 += 1
return str(num1)
re_sub2 = re.sub(r'\d+', numplus, '数学:59 英语:59')
print(re_sub2) # 数学:60 英语:60 执行函数后的运行结果!
# re.split(正则, string)
re_split = re.split(r'[,:]', '数学:59 英语:59')
print(re_split) # ['数学', '59 英语', '59']
# 贪婪模式: 总是尽可能多的去匹配
msg5 = 'abc123abc'
print(re.match(r'abc(\d+)', msg5)) # <re.Match object; span=(0, 6), match='abc123'>
print(re.match(r'abc(\d*)', msg5)) # <re.Match object; span=(0, 6), match='abc123'>
print(re.match(r'abc(\d?)', msg5)) # <re.Match object; span=(0, 4), match='abc1'>
# re中方法总结
match(pattern, string) 从开头开始匹配,匹配一次
search(pattern, string) 整个字符串匹配一次就完事
findall(pattern, string) 整个字符串全部匹配
sub(pattern, new, str) 替换
split(pattern, str) 切割
文章来源地址https://www.toymoban.com/news/detail-419904.html
文章来源:https://www.toymoban.com/news/detail-419904.html
到了这里,关于从零学习python - 14正则表达式的始末的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!