正则表达式 & python re模块
常用的正则匹配工具
在线匹配工具:
https://tool.oschina.net/regex/
匹配单个字符与数字
| 匹配 | 说明 |
|---|---|
| . | 匹配除换行符以外的任意字符,当flags被设置为re.S时,可以匹配包含换行符以内的所有字符 |
| [] | 里面是字符集合,匹配[]里任意一个字符 |
| [0123456789] | 匹配任意一个数字字符 |
| [0-9] | 匹配任意一个数字字符 |
| [a-z] | 匹配任意一个小写英文字母字符 |
| [A-Z] | 匹配任意一个大写英文字母字符 |
| [A-Za-z] | 匹配任意一个英文字母字符,等于 [a-zA-Z] |
| [A-Za-z0-9] | 匹配任意一个数字或英文字母字符 |
| [^lucky] | []里的^称为脱字符,表示非,匹配不在[]内的任意一个字符 |
| ^[lucky] | 以[]中内的某一个字符作为开头 |
| \d | 匹配任意一个数字字符,相当于[0-9] |
| \D | 匹配任意一个非数字字符,相当于[^0-9] |
| \w | 匹配字母、下划线、数字中的任意一个字符,相当于[0-9A-Za-z_] |
| \W | 匹配非字母、下划线、数字中的任意一个字符,相当于[^0-9A-Za-z_] |
| \s | 匹配空白符(空格、换页、换行、回车、制表),相当于[ \f\n\r\t] |
| \S | 匹配非空白符(空格、换页、换行、回车、制表),相当于[^ \f\n\r\t] |
| \n | 匹配一个换行符 |
| \t | 匹配一个制表符 |
| \r | 匹配一个回车符 |
匹配锚字符
锚字符:用来判定是否按照规定开始或者结尾
| 匹配 | 说明 |
|---|---|
| ^ | 行首匹配,和[]里的^不是一个意思 |
| $ | 行尾匹配 |
| \A | |
| \Z | 匹配字符串的结尾,和$的区别是\Z只匹配整个字符串的结尾,即使在re.M模式下也不会匹配其他行的行尾 |
限定符
限定符用来指定正则表达式的一个给定组件必须要出现多少次才能满足匹配。有 * 或 + 或 ? 或 {n} 或 {n,} 或 {n,m} 共6种。
| 匹配 | 说明 |
|---|---|
| (xyz) |
匹配括号内的xyz,作为一个整体去匹配一个单元或者一个子存储 1.作为一个运算符的单元,比如改变加减乘除的执行的顺序 2.作为子存储,将他的值拿出来 |
| x? | 匹配0个或者1个x,非贪婪匹配 |
| x* | 匹配0个或任意多个x |
| x+ | 匹配至少一个x |
| x{n} | 确定匹配n个x,n是非负数 |
| x{n,} | 至少匹配n个x |
| x{n,m} | 匹配至少n个最多m个x |
| x|y | |表示或的意思,匹配x或y |
贪婪匹配和惰性匹配
.* 贪婪匹配, 尽可能多的去匹配结果 .*? 惰性匹配, 尽可能少的去匹配结果 -> 回溯
正则匹配案例
# [] # 原子表
[a]
[ab] # 匹配a或者b
[abc] # 匹配a或者b后者c
[123] # 匹配1或者2或者3
[0-9] # 匹配任意一位数字
[a-z] # 匹配任意以为小写字母
[A-Z] # 匹配任意一位大写字母
[a-zA-Z] # 匹配任意大小写字母
# [][]
[abc][0-9] # 它代表什么意思? 匹配a或者b后者c和任意一位数字 比如:a1
# 匹配手机号码
1[3-9][0-9]{9} # {9} 代表前面的[0-9]9位
# ^ 限制开头 $ 限制结尾 一般用于组合
^1[3-9][0-9]{9}$ # 完全匹配 匹配的字符串中 必须完全符合才算匹配成功
15611833906 # 符合
156118339067 # 不符合
# {} 代表前面正则匹配的n词
[a-z]{2} # 匹配俩位小写字母
[a-z][a-z] # 等同于上方
# {m,n} m-n之间的
[a-z]{2,5} # 匹配2-5个小写字母
# {m,} # 至少m个
[a-z]{2,} # 至少匹配2个小写字母
# ? 可有可无
-?[1-9] # 匹配正负1-9
# . 匹配换行符以外的任意字符
a x z
# * 代表前面的0次到多次 {0,}
# .* 组合 了解 贪婪模式 匹配换行符以外的任意字符任意次
# .*? 组合 重要!!!!!! 非贪婪模式 匹配换行符以外的任意字符任意次
# + 匹配一次到多次 {1,}
# .+? 非贪婪模式 匹配换行符以外的任意字符至少1次
# | 代表或
[a-z]|[0-9] # 匹配字母或数字
通用函数
获取匹配结果:
(1)使用 group() 方法 获取到匹配的值
(2)groups() 返回一个包含所有小组字符串的元组(也就是自存储的值),从 1 到 所含的小组号。
match()函数
原型:
def match(pattern, string, flags=0)
功能:
(1)匹配成功返回匹配的对象
(2)匹配失败返回 None
获取匹配结果
(1)使用group()方法 获取到匹配的值
(2)groups() 返回一个包含所有小组字符串的元组,从 1 到 所含的小组号。
注意:必须从字符串开头匹配,只匹配一次。
和search一样,区别在于 match必须从第一位匹配 相当于多了^ ,其它都一样
参数
pattern: 匹配的正则表达式(一种字符串的模式)。
string: 要匹配的字符串。
flags:标识位,用于控制正则表达式的匹配方式。
示例
import re
res = re.match('\d{2}','123')
print(res.group())
#给当前匹配到的结果起别名
s = '3G4HFD567'
x = re.match("(?P<value>\d+)",s)
print(x.group(0))
print(x.group('value'))
12
3
3
示例:
import re
print(re.match("abc", "abcd").group())
print(re.match("abc", "xabcd"))
print(re.match("abc+", "abccccd")) # + 代表前面的正则的一个到多个
print(re.match("[a-z]+", "abccccd")) # + 代表前面的正则的一个到多个
print(re.match("1[3-9][0-9]{9}", "177123456789"))
print(re.match("1[3-9][0-9]{9}", "2177123456789"))
abc
None
<re.Match object; span=(0, 6), match='abcccc'>
<re.Match object; span=(0, 7), match='abccccd'>
<re.Match object; span=(0, 11), match='17712345678'>
None
search()函数
原型
def search(pattern, string, flags=0)
功能
(1)扫描整个字符串string,并返回第一个pattern模式成功的匹配
(2)匹配失败 返回 None
参数
pattern: 匹配的正则表达式(一种字符串的模式)。
string:要匹配的字符串。
flags:标识位,用于控制正则表达式的匹配方式。
注意: 只要字符串包含就可以;只匹配一次。
示例
import re
res = re.search('[a-z]', '131A3ab889s')
print(res)
print(res.group()
与search的区别
相同点: 都只匹配一次
不同点:
(1)search是在要匹配的字符串中 包含正则表达式的内容就可以
(2)match 必须第一位就开始匹配 否则匹配失败
示例
import re
print(re.search("a", '123456')) # 不匹配
print(re.search("[a-z]", '123456')) # 不匹配
print(re.search("[a-z]", '123x456')) # 完全匹配
print(re.search("[a-z][a-z]", '123x456')) # 不匹配
print(re.search("[a-z][a-z]", '123ab456')) # 完全匹配
print("==========================")
print(re.search("[a-z][a-z]", '123ax456b')) # 完全匹配
print(re.search("1[3-9][0-9]{9}", '15611833906')) # 完全匹配
print(re.search("1[3-9][0-9]{9}", '15611833906a')) # 包含 也就是字符串中包含我要的则为成功
print(re.search("1[3-9][0-9]{9}", 'x15611833906a')) # 包含 也就是字符串中包含我要的则为成功
print(re.search("^1[3-9][0-9]{9}", 'x15611833906a')) # 不匹配
print("==========================")
print(re.search("^1[3-9][0-9]{9}", '15611833906a')) # 完全匹配
print(re.search("^1[3-9][0-9]{9}$", '15611833906a')) # 不匹配
print(re.search("^1[3-9][0-9]{9}$", '15611833906')) # 完全匹配
print(re.search("^1[3-9][0-9]{9}$", '1561183390')) # 不匹配
print(re.search("^1[3-9][0-9]{9}$", '15611833906').group()) # 完全匹配
None
None
<re.Match object; span=(3, 4), match='x'>
None
<re.Match object; span=(3, 5), match='ab'>
==========================
<re.Match object; span=(3, 5), match='ax'>
<re.Match object; span=(0, 11), match='15611833906'>
<re.Match object; span=(0, 11), match='15611833906'>
<re.Match object; span=(1, 12), match='15611833906'>
None
==========================
<re.Match object; span=(0, 11), match='15611833906'>
None
<re.Match object; span=(0, 11), match='15611833906'>
None
15611833906
findall()函数(返回列表)
原型
def findall(pattern, string, flags=0)
功能
扫描整个字符串string,并返回所有匹配的pattern模式结果的字符串列表
参数
pattern: 匹配的正则表达式(一种字符串的模式)。
string: 要匹配的字符串。
flags:标识位,用于控制正则表达式的匹配方式。
示例
import re
myStr = """
<a href="http://www.baidu.com">百度</a>
<A href="http://www.taobao.com">淘宝</A>
<a href="http://www.id97.com">电
影网站</a>
<i>我是倾斜1</i>
<i>我是倾斜2</i>
<em>我是倾斜2</em>
"""
# html里是不区分大小写
# (1)给正则里面匹配的 加上圆括号 会将括号里面的内容进行 单独的返回
print(re.findall("(<a href=\"http://www\.(.*?)\.com\">(.*?)</a>)",myStr))
# 括号的区别
print(re.findall("<a href=\"http://www\..*?\.com\">.*?</a>",myStr))
#(2) 不区分大小写的匹配
print(re.findall("<a href=\"http://www\..*?\.com\">.*?</a>",myStr,re.I))
print(re.findall("<[aA] href=\"http://www\..*?\.com\">.*?</[aA]>",myStr))
# 使.支持换行匹配
print(re.findall("<a href="http://www..?.com">.?</a>",myStr,re.S))
# 支持换行 支持不区分大小写匹配
print(re.findall("<a href="http://www..?.com">.?</a>",myStr,re.S|re.I))
[('<a href="http://www.baidu.com">百度</a>', 'baidu', '百度')]
['<a href="http://www.baidu.com">百度</a>']
['<a href="http://www.baidu.com">百度</a>', '<A href="http://www.taobao.com">淘宝</A>']
['<a href="http://www.baidu.com">百度</a>', '<A href="http://www.taobao.com">淘宝</A>']
finditer()函数
原型
def finditer(pattern, string, flags=0)
功能
与findall()类似,返回一个迭代器。
参数
pattern: 匹配的正则表达式(一种字符串的模式)。
string: 要匹配的字符串。
flags:标识位,用于控制正则表达式的匹配方式。
import re
res = re.finditer('\w', '12hsakda1')
print(res)
print(next(res))
print(next(res))
print(next(res))
print("======================")
for i in res:
print(i)
#print(i.group())
print("======================")
# 当前为贪婪
List = re.finditer('<b>.*</b>', '<b>b标签</b><b>加粗</b>')
print(next(List).group()) # 一般用于节省内存
for i in List:
print(i.group())
print("======================")
# 拒绝贪婪 以后使用这个
List = re.finditer('<b>.*?</b>', '<b>b标签</b><b>加粗</b>')
for i in List:
print(i.group())
print("======================")
# () 子存储 内容单独返回
List = re.finditer('<b>(.*?)</b>', '<b>b标签</b><b>加粗</b>')
for i in List:
print(i.group())
List = re.findall('(<b>(.*?)</b>)', '<b>b标签</b><b>加粗</b>')
print(List)
<callable_iterator object at 0x000001C235ED0760>
<re.Match object; span=(0, 1), match='1'>
<re.Match object; span=(1, 2), match='2'>
<re.Match object; span=(2, 3), match='h'>
======================
<re.Match object; span=(3, 4), match='s'>
<re.Match object; span=(4, 5), match='a'>
<re.Match object; span=(5, 6), match='k'>
<re.Match object; span=(6, 7), match='d'>
<re.Match object; span=(7, 8), match='a'>
<re.Match object; span=(8, 9), match='1'>
======================
<b>b标签</b><b>加粗</b>
======================
<b>b标签</b>
<b>加粗</b>
======================
<b>b标签</b>
<b>加粗</b>
[('<b>b标签</b>', 'b标签'), ('<b>加粗</b>', '加粗')]
split()函数
作用:切割字符串
原型:
def split(patter, string, maxsplit=0, flags=0)
参数:
pattern 正则表达式
string 要拆分的字符串
maxsplit 最大拆分次数 默认拆分全部
flags 修正符
示例
import re
myStr = "asdas\rd&a\ts12d\n*a3sd@a_1sd"
#通过特殊字符 对其进行拆分 成列表
print(re.split("[^a-z]",myStr))
print(re.split("\W",myStr))
['asdas', 'd', 'a', 's', '', 'd', '', 'a', 'sd', 'a', '', 'sd']
['asdas', 'd', 'a', 's12d', '', 'a3sd', 'a_1sd']
修正符
作用:对正则进行修正
使用 search/match/findall/sub/subn/finditer 等函数 flags参数的使用
修正符:
re.I 不区分大小写匹配
re.M 多行匹配 影响到^ 和 $ 的功能
re.S 使.可以匹配换行符 匹配任意字符
re.I
import re
print(re.findall('[a-z]','AaBb'))
print(re.findall('[a-z]','AaBb', flags=re.I))
['a', 'b']
['A', 'a', 'B', 'b']
re.M(实际没啥用,不用过多关注,了解即可)
re.M 对于^$影响
\A 和 \Z 和^ $ 一样的 只有在re.M时有区别
import re
myStr = """asadasdd1\nbsadasdd2\ncsadasdd3"""
print(re.findall('^[a-z]',myStr, ))
print(re.findall('\A[a-z]',myStr))
print(re.findall('\d$',myStr))
print(re.findall('\d\Z',myStr))
print("====================")
# re.M
print(re.findall('^[a-z]',myStr, flags=re.M))
print(re.findall('\A[a-z]',myStr, flags=re.M))
print(re.findall('\d$',myStr, flags=re.M))
print(re.findall('\d\Z',myStr, flags=re.M))
['a']
['a']
['3']
['3']
====================
['a', 'b', 'c']
['a']
['1', '2', '3']
['3']
re.S
import re
print(re.findall('<b>.*?</b>','<b>b标签</b>'))
print(re.findall('<b>.*?</b>','<b>b标\n签</b>', flags=re.S))
['<b>b标签</b>']
['<b>b标\n签</b>']
示例:
import re
# re.I 是匹配对大小写不敏感
# re.M 多行匹配,影响到^和$
# re.S 使.匹配包括换行符在内的所有字符
myStr = """
<a href="http://www.baidu.com">百度1</a>
<A href="http://www.baidu.com">百度</A>
<a href='http://www.baidu.com'>百度2</a>
<a href='http://www.tengxun.com'>腾
讯</a>
"""
# 匹配所有的正常的a链接 小写
print(re.findall("<a href=\"http://www.baidu.com\">百度</a>", ""))
# 修正符号
# 匹配大小写
print(re.findall('(<a href="(.*?)">(.*?)</a>)', myStr, re.I))
# 匹配大小写 多行匹配 可以匹配换行符
print(re.findall('(<a href=[\'"](.*?)[\'"]>(.*?)</a>)', myStr, re.I|re.M|re.S))
[]
[('<a href="http://www.baidu.com">百度1</a>', 'http://www.baidu.com', '百度1'), ('<A href="http://www.baidu.com">百度</A>', 'http://www.baidu.com', '百度')]
[('<a href="http://www.baidu.com">百度1</a>', 'http://www.baidu.com', '百度1'), ('<A href="http://www.baidu.com">百度</A>', 'http://www.baidu.com', '百度'), ("<a href='http://www.baidu.com'>百度2</a>", 'http://www.baidu.com', '百度2'), ("<a href='http://www.tengxun.com'>腾\n讯</a>", 'http://www.tengxun.com', '腾\n讯')]
正则高级:分组&起名称
概念
处理简单的判断是否匹配之外,正则表达式还有提取子串的功能,用()表示的就是要提取的分组
import re
#给当前匹配到的结果起别名
s = '3G4HFD567'
x = re.match("(?P<value>\d+)",s)
print(x.group(0))
print(x.group('value'))
3
3
说明:
(1)正则表达式中定义了组,就可以在Match对象上用group()方法提取出子串来
(2)group(0)永远是原始字符串,group(1)、group(2)……表示第1、2、……个子串
正则高级:编译
概念
当在python中使用正则表达式时,re模块会做两件事,一件是编译正则表达式,如果表达式的字符串本身不合法,会报错。另一件是用编译好的正则表达式提取匹配字符串
编译优点
如果一个正则表达式要使用几千遍,每一次都会编译,出于效率的考虑进行正则表达式的编译,就不需要每次都编译了,节省了编译的时间,从而提升效率
compile()函数
原型
def compile(pattern, flags=0)
作用
将pattern模式编译成正则对象
参数
pattern: 匹配的正则表达式(一种字符串的模式)。
flags:标识位,用于控制正则表达式的匹配方式。
flags
re.I:是匹配对大小写不敏感。
re.M: 多行匹配,影响到^和$。
re.S:使.匹配包括换行符在内的所有字符。
返回值
编译好的正则对象
示例
import re
re_phone = re.compile(r"(0\d{2,3}-\d{7,8})")
print(re_phone, type(re_phone))
re.compile('(0\\d{2,3}-\\d{7,8})') <class 're.Pattern'>
编译后其他方法的使用
原型
def match(self, string, pos=0, endpos=-1)
def search(self, string, pos=0, endpos=-1)
def findall(self, string, pos=0, endpos=-1)
def finditer(self, string, pos=0, endpos=-1)
参数
string: 待匹配的字符串。
pos: 从string字符串pos下标开始。
endpos: 结束下标。
正则高级:贪婪与非贪婪
贪婪模式
贪婪概念:匹配尽可能多的字符
(1) .+ 匹配换行符以外的字符至少一次
(2) .* 匹配换行符以外的字符任意次
非贪婪模式
非贪婪概念:尽可能少的匹配称为非贪婪匹配,*?、+?即可
.+? 匹配换行符以外的字符至少一次 拒绝贪婪
.*? 匹配换行符以外的字符任意次 拒绝贪婪
示例:
import re
str = "<b>加粗</b><b>加粗的</b><b>加粗的的</b>"
# 非贪婪
print(re.search('<b>.*?</b>', str))
print(re.findall('<b>.*?</b>', str))
# 贪婪
print(re.search('<b>.*</b>', str))
print(re.findall('<b>.*</b>', str))
# ()
# val = re.search('<b>(.*?)</b>', str)
val = re.search('<b>.*?</b>', str)
print(val.group())
print(val.groups()) # 如果有多个括号的时候 可以使用groups将值单独取出
<re.Match object; span=(0, 9), match='<b>加粗</b>'>
['<b>加粗</b>', '<b>加粗的</b>', '<b>加粗的的</b>']
<re.Match object; span=(0, 30), match='<b>加粗</b><b>加粗的</b><b>加粗的的</b>'>
['<b>加粗</b><b>加粗的</b><b>加粗的的</b>']
<b>加粗</b>
()
浙公网安备 33010602011771号