正则:对字符串进行的一种过滤逻辑
需要用到的模块:re 提供正则相关的操作
import re
目录
match 匹配
# match 匹配,只会从头匹配
msg1 = '庆余年小时代秋蝉传闻中的陈芊芊'
'''
compile 函数根据一个模式字符串和可选的标志参数生成一个正则表达式对象。该对象拥有一系列方法用于正则表达式匹配和替换。
re 模块也提供了与这些方法功能完全一致的函数,这些函数使用一个模式字符串做为它们的第一个参数。
'''
pattern = re.compile('小时代')
res1 = pattern.match(msg1)
print('msg1中是否有小时代?',res1)
# msg1中是否有小时代? None
msg2 = '庆余年小时代秋蝉传闻中的陈芊芊'
pattern2 = re.compile('庆余年')
res2 = pattern2.match(msg2)
print('msg2中是否有庆余年?',res2)
# msg2中是否有庆余年? <_sre.SRE_Match object; span=(0, 3), match='庆余年'>
re.match
# re.match 只要从开头匹配不成功就返回None
msg3 = '庆余年小时代秋蝉传闻中的陈芊芊'
res3 = re.match('小时代',msg3)
print(res3) # None
re.search(pattern,string)
# re.search(pattern,string) 匹配整个字符串(只要找到一个匹配的,就不再往下找了)。span【匹配的位置】,group【匹配的内容】
res4 = re.search('小时代',msg3)
print('res4:',res4)
# res4: <_sre.SRE_Match object; span=(3, 6), match='小时代'>
print(res4.span()) # (3, 6)
print(res4.group()) # 小时代
re模块符号大全
模式 | 描述 |
---|---|
^ | 匹配字符串的开头 |
$ | 匹配字符串的末尾。 |
. | 匹配任意字符,除了换行符,当re.DOTALL标记被指定时,则可以匹配包括换行符的任意字符。 |
[...] | 用来表示一组字符,单独列出:[amk] 匹配 'a','m'或'k' |
[^...] | 不在[]中的字符:[^abc] 匹配除了a,b,c之外的字符。 |
re* | 匹配0个或多个的表达式。 |
re+ | 匹配1个或多个的表达式。 |
re? | 匹配0个或1个由前面的正则表达式定义的片段,非贪婪方式 |
re{ n} | 匹配n个前面表达式。例如,"o{2}"不能匹配"Bob"中的"o",但是能匹配"food"中的两个o。 |
re{ n,} | 精确匹配n个前面表达式。例如,"o{2,}"不能匹配"Bob"中的"o",但能匹配"foooood"中的所有o。"o{1,}"等价于"o+"。"o{0,}"则等价于"o*"。 |
re{ n, m} | 匹配 n 到 m 次由前面的正则表达式定义的片段,贪婪方式 |
a|b | 匹配a或b |
(re) | 匹配括号内的表达式,也表示一个组 |
(?imx) | 正则表达式包含三种可选标志:i, m, 或 x 。只影响括号中的区域。 |
(?-imx) | 正则表达式关闭 i, m, 或 x 可选标志。只影响括号中的区域。 |
(?: re) | 类似 (...), 但是不表示一个组 |
(?imx: re) | 在括号中使用i, m, 或 x 可选标志 |
(?-imx: re) | 在括号中不使用i, m, 或 x 可选标志 |
(?#...) | 注释. |
(?= re) | 前向肯定界定符。如果所含正则表达式,以 ... 表示,在当前位置成功匹配时成功,否则失败。但一旦所含表达式已经尝试,匹配引擎根本没有提高;模式的剩余部分还要尝试界定符的右边。 |
(?! re) | 前向否定界定符。与肯定界定符相反;当所含表达式不能在字符串当前位置匹配时成功。 |
(?> re) | 匹配的独立模式,省去回溯。 |
\w | 匹配数字字母下划线 |
\W | 匹配非数字字母下划线 |
\s | 匹配任意空白字符,等价于 [\t\n\r\f]。 |
\S | 匹配任意非空字符 |
\d | 匹配任意数字,等价于 [0-9]。 |
\D | 匹配任意非数字 |
\A | 匹配字符串开始 |
\Z | 匹配字符串结束,如果是存在换行,只匹配到换行前的结束字符串。 |
\z | 匹配字符串结束 |
\G | 匹配最后匹配完成的位置。 |
\b | 匹配一个单词边界,也就是指单词和空格间的位置。例如, 'er\b' 可以匹配"never" 中的 'er',但不能匹配 "verb" 中的 'er'。 |
\B | 匹配非单词边界。'er\B' 能匹配 "verb" 中的 'er',但不能匹配 "never" 中的 'er'。 |
\n, \t, 等。 | 匹配一个换行符。匹配一个制表符, 等 |
\1...\9 | 匹配第n个分组的内容。 |
\10 | 匹配第n个分组的内容,如果它经匹配。否则指的是八进制字符码的表达式。 |
注意:表中re指的是表达式,而不是字面的re这两个字母
特殊字符类:
实例 | 描述 |
---|---|
. | 匹配除 "\n" 之外的任何单个字符。要匹配包括 '\n' 在内的任何字符,请使用象 '[.\n]' 的模式。 |
\d | 匹配一个数字字符。等价于 [0-9]。 |
\D | 匹配一个非数字字符。等价于 [^0-9]。 |
\s | 匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。 |
\S | 匹配任何非空白字符。等价于 [^ \f\n\r\t\v]。 |
\w | 匹配包括下划线的任何单词字符。等价于'[A-Za-z0-9_]'。 |
\W | 匹配任何非单词字符。等价于 '[^A-Za-z0-9_]'。 |
re.findall()
# 匹配形如:字母 数字 字母 形式的内容,如a2b,b3n,h5n
str = 'aswf87h8u9j0kmnj3b5h6y'
# re.search() 找到第一个后就不再往下找了
res5 = re.search('[a-z][0-9][a-z]',str) # []:在正则中表示一个范围
print(res5.group()) # h8u
# re.findall() 找到所有的匹配内容到列表中
res6 = re.findall('[a-z][0-9][a-z]',str) # []:在正则中表示一个范围
print(res6) # ['h8u', 'j0k', 'j3b', 'h6y']
匹配次数约束正则符号
匹配次数约束正则符号: * 匹配>=0次 + 匹配>=1次 ? 匹配0或1次 {m}验证前面的匹配m次 {m,}验证前面的匹配m或者多次 {m,n}验证前面的匹配[m,n]次 ^ 开头 $ 结尾
str = 'aswf87h8u9j0kmnj3b5h6y'
res7 = re.findall('[a-z][0-9]+[a-z]',str) # + 在谁的后面表示对谁加约束,现在是指数字至少一次
print(res7) # ['f87h', 'u9j', 'j3b', 'h6y']
# 验证是否为qq号码 5-11位
tel = input('请输入手机号码:')
res8 = re.match('^[1-9][0-9]{4,10}$',tel)
print(res8)
# 用户名可以使字母或数字,不能数字开头,用户名长度必须6位以上
uname = 'kh31j3n2m'
res = re.match('^[a-zA-Z][0-9a-zA-Z]{5,}$',uname)
print(res)
# \d: 匹配任意数字,等价于[0-9] # \D: 匹配任意非数字 # \w: 字母数字下划线 # \W:非字母数字下划线 # \b: 边界(挨着空格) # \s: 匹配空格 # \S: 非空格
uname = 'kh31j3n2m'
res = re.match('^[a-zA-Z]\w{5,}$',uname)
print(res)
# 找出以.py结尾的文件
message = 'a*py as.py bb.jpg kn.py ec.docx'
result = re.findall(r'\w*\.py\b',message)
print(result) # ['as.py', 'kn.py']
分组匹配
# 匹配0-100之间的数字
res = re.match(r'[1-9]?\d?$|100$','96')
print(res) # <_sre.SRE_Match object; span=(0, 2), match='96'>
# 匹配邮箱
# (126|163|qq) :整体的或者,即126或163或qq
# [126|163|qq] : 单个的或者,即1或2或6或6或3...
re.match(r'\w{5,20}@(126|163|qq)\.(com|cn)$',str)
# 匹配不以4,7结尾的手机号
re.match(r'1\d{9}[0-35-689]',str)
# 带区号的电话号码
phone = '010-12786548'
res11 = re.match(r'(\d{3}|\d{4})-(\d{8})$', phone)
print(res11)
# 分别提取
print(res11.group())
# () 表示分组。
print(res11.group(1)) # 第一组的内容
print(res11.group(2)) # 第二组的内容
# 执行结果:
# 010-12786548
# 010
# 12786548
匹配HTML标签示例:
# 匹配标签内的内容
str = '<body>haha!amaizing</body>'
res = re.match(r'<[0-9a-zA-Z]+>(.+)</[0-9a-zA-Z]+>$',str)
print(res) # <_sre.SRE_Match object; span=(0, 26), match='<body>haha!amaizing</body>'>
print(res.group()) # <body>haha!amaizing</body>
print(res.group(1)) # haha!amaizing
str2 = '<html><body>haha!amaizing</body><html>'
res2 = re.match(r'<[0-9a-zA-Z]+>(.+)</[0-9a-zA-Z]+>',str2) # 需要将$去掉,+具有贪婪模式
print(res2) # <_sre.SRE_Match object; span=(0, 32), match='<html><body>haha!amaizing</body>'>
# 如果是非成对的html标签,还会匹配成功吗? 这种正则下,答案是会的!!!
str3 = '<html><body>haha!amaizing</p><html>'
res3 = re.match(r'<[0-9a-zA-Z]+>(.+)</[0-9a-zA-Z]+>',str3) # 需要将$去掉,+具有贪婪模式
print(res3) # _sre.SRE_Match object; span=(0, 29), match='<html><body>haha!amaizing</p>'>
# 如果需要匹配成对的HTML标签,就需要用到分组匹配
# 单对html标签的时候
str4 = '<body>haha!amaizing</p>'
str5 = '<body>haha!amaizing</body>'
res4 = re.match(r'<([0-9a-zA-Z]+)>(.+)</\1>$',str4) # \1表示与第一组同
print(res4) # None
res5 = re.match(r'<([0-9a-zA-Z]+)>(.+)</\1>$',str5)
print(res5) # <_sre.SRE_Match object; span=(0, 26), match='<body>haha!amaizing</body>'>
print(res5.group(1)) # body
print(res5.group(2)) # haha!amaizing
# 2对html标签的时候
str6 = '<html><body>haha!amaizing</body></html>'
res6 = re.match(r'<([0-9a-zA-Z]+)><([0-9a-zA-Z]+)>(.+)</\2></\1>$',str6)
print(res6) # <_sre.SRE_Match object; span=(0, 39), match='<html><body>haha!amaizing</body></html>'>
print(res6.group(1)) # html
print(res6.group(2)) # body
print(res6.group(3)) # haha!amaizing
# PS:有几个(),就有几个分组,就可以打印几个group
# 给分组自定义名字 (?P<名字>正则) (?P<=名字)
str6 = '<html><body>haha!amaizing</body></html>'
res6 = re.match(r'<(?P<name1>[0-9a-zA-Z]+)><(?P<name2>[0-9a-zA-Z]+)>(.+)</(?P=name2)></(?P=name1)>$',str6)
print('起名的方式---',res6) # 起名的方式--- <_sre.SRE_Match object; span=(0, 39), match='<html><body>haha!amaizing</body></html>'>
re.sub()
# re.sub(正则,'新内容',str) 将str中正则匹配到的替换为新内容
res = re.sub(r'\d+','90','数学:89,英语:99')
print(res) # 数学:90,英语:90
# 使用函数对匹配到的内容进行操作
def func(temp):
num = temp.group() # 正则匹配到的内容
num1 = int(num) + 1
return str(num1)
res2 = re.sub(r'\d+',func,'数学:89,英语:99')
print(res2) # 数学:90,英语:100
re.split()
# re.split()
res = re.split(r'[,:]','数学:89,英语:99') # 将str中遇到,或:就分割,放到list中
print(res) # ['数学', '89', '英语', '99']
贪婪与非贪婪
# 贪婪与非贪婪
# python中默认量词(* ? +等)是贪婪的
msg = 'abc1212abc13'
res = re.match(r'abc(\d+)',msg)
print(res) # <_sre.SRE_Match object; span=(0, 7), match='abc1212'>
# 本来取到abc1就满足条件了,但是+是贪婪的,会一直取完所有满足的
# 非贪婪则相反,总是尝试匹配尽可能少的
# 将贪婪模式变为非贪婪的,只需要加?
res2 = re.match(r'abc(\d+?)',msg)
print(res2) # <_sre.SRE_Match object; span=(0, 4), match='abc1'>