正则表达式
动机
- 文本处理已经成为计算机的常见工作之一
- 对文本内容的搜索,定位,提取是逻辑比较复杂的工作
- 为了快速解决上述问题,产生了正则表达式技术
定义
即文本的高级匹配模式,提供搜索,替代等功能。其本质是一系列由特殊符号组成的字串,这个字串即正则表达式。
匹配原理
由普通字符和特殊符号组成字符串,通过描述字符的重复和位置等行为,达到匹配某一类字符串的目的。
特点
- 方便文本处理
- 支持语言众多
- 使用灵活多样
元字符的使用
普通字符
元字符:a
,b
,c
...
匹配规则:每个字符匹配对应的字符
import re
In [15]: re.findall("hello","hello world")
Out[15]: ['hello']
In [19]: re.findall("你好","你好北京")
Out[19]: ['你好']
或
元字符:|
匹配规则:匹配|
两边任意一个正则表达式
import re
In [8]: re.findall('ab|cd','abcdefghiabhfjdcd')
Out[8]: ['ab', 'cd', 'ab', 'cd']
匹配单个字符
元字符:.
匹配规则:匹配除换行外的任意字符
import re
In [9]: re.findall('f.o','foo is not a fao')
Out[9]: ['foo', 'fao']
In [12]: re.findall('f.o','f好o')
Out[12]: ['f好o']
In [18]: re.findall('王..','王小刚,王小明,张小米')
Out[18]: ['王小刚', '王小明']
匹配开始位置
元字符:^
匹配规则:匹配目标字符串的开头位置
import re
In [19]: re.findall('^Tom','Hi,Tom')
Out[19]: []
In [20]: re.findall('^Tom','Tom is a boy')
Out[20]: ['Tom']
匹配结束位置
元字符:$
匹配规则:匹配字符串的结束位置
import re
In [23]: re.findall('Tom$','Hi,Tom')
Out[23]: ['Tom']
In [24]: re.findall('Tom$','Hi,Tom.')
Out[24]: []
匹配重复一
元字符:*
匹配规则:匹配*
前面的字符出现0次或多次
import re
In [25]: re.findall('fo*','fooooo')
Out[25]: ['fooooo']
In [26]: re.findall('fo*','foaooo')
Out[26]: ['fo']
In [27]: re.findall('fo*','faooo')
Out[27]: ['f']
In [28]: re.findall('fo*','afoo')
Out[28]: ['foo']
In [33]: re.findall("fo*","fadsfafoooafo")
Out[33]: ['f', 'f', 'fooo', 'fo']
匹配重复二
元字符:+
匹配规则:匹配前面的字符出现1次或多次
import re
In [30]: re.findall('fo+','fasddsfdfooafo')
Out[30]: ['foo', 'fo']
匹配重复三
元字符:?
匹配规则:匹配前面的字符出现0次或1次
import
In [38]: re.findall('fo?','fadsfsfoooadfo')
Out[38]: ['f', 'f', 'fo', 'fo']
匹配重复四
元字符:{n}
匹配规则:匹配指定的重复次数
import re
In [2]: re.findall("fo{3}","fafoodffoooafooooo")
Out[2]: ['fooo', 'fooo']
匹配重复五
元字符:{m,n}
匹配规则:匹配前面的正则表达式m-n
次
import re
In [3]: re.findall("fo{2,4}","fafoodffoooafooooo")
Out[3]: ['foo', 'fooo', 'foooo']
匹配字符集合
元字符:[字符集]
匹配规则:匹配任意一个字符集中的字符
# [abc123] a b c 2 3
# [a-z] 匹配任意小写字母
# [A-Z] 匹配任意大写字母
# [_123a-z] 匹配1 2 3 任意小写字母
import re
In [4]: re.findall('^[A-Z][a-z]*','Boy,BOY')
Out[4]: ['Boy']
匹配字符集
元字符:[^...]
匹配规则:字符集取非,除列出的字符之外任意一个字符
import re
In [6]: re.findall('[^abc]','acbdce')
Out[6]: ['d', 'e']
In [9]: re.findall('[^ ]+','a little boy')
Out[9]: ['a', 'little', 'boy']
匹配任意(非)数字字符
元字符:\d
,\D
匹配规则:\d
匹配任意数字字符[0-9]
,\D
匹配任意非数字字符[^0-9]
import re
In [10]: re.findall('\d','123abc456')
Out[10]: ['1', '2', '3', '4', '5', '6']
In [14]: re.findall('^1\d{10}','18888886666"')
Out[14]: ['18888886666"']
匹配任意(非)普通字符
元字符:\w
,\W
匹配规则:\w
普通字符 [_0-9a-zA-Z]
,也能匹配普通汉字;\W
非普通字符
import re
In [16]: re.findall('\w+','jkds$%&fhdsbgfdb#gdbg@')
Out[16]: ['jkds', 'fhdsbgfdb', 'gdbg']
In [17]: re.findall('\W+','jkds$%&fhdsbgfdb#gdbg@')
Out[17]: ['$%&', '#', '@']
匹配任意(非)空字符
元字符:\s
,\S
匹配规则:\s
匹配任意空字符[ \r\t\n\v\f]
;\S
匹配任意非空字符
import re
In [19]: re.findall('\w+\s+\w+','hello world')
Out[19]: ['hello world']
In [20]: re.findall('\w+\s+\w+','hello world')
Out[20]: ['hello world']
In [22]: re.findall('\S+','I am a little boy')
Out[22]: ['I', 'am', 'a', 'little', 'boy']
匹配字符串位置
元字符:\A
,\Z
匹配规则:\A
匹配字符串开头位置^
;\Z
匹配字符串结尾位置$
import re
In [23]: re.findall('\Ahello','hello this is tome')
Out[23]: ['hello']
In [26]: re.findall('me\Z','hello this is tome')
Out[26]: ['me']
绝对匹配:正则表达式要完全匹配目标字符串内容
在正则表达式开始和结束位置加上^
,$
(或者\A
,\Z
)。这样正则表达式必须匹配整个目标字符串才会有结果
匹配(非)单词边界
普通字符和非普通字符交界认为是单词边界
元字符:\b
,\B
匹配规则:\b
匹配单词边界位置; \B
匹配非单词边界位置
import re
In [27]: re.findall(r'num\b','num#abc$')
Out[27]: ['num']
In [32]: re.findall(r'\Bis','This makes me happy')
Out[32]: ['is']
总结
匹配单个字符:a
,.
,\d
,\D
,\w
,\W
,\s
,\S
,[...]
,[^...]
匹配重复:*
,+
,?
,{n}
,{m,n}
匹配位置:^
,$
,\A
,\Z
,\b
,\B
其他:|
,()
,\
正则表达式转义
正则中的特殊符号
.
*
+
?
^
$
[]
{}
()
|
\
正则表达式如果匹配特殊字符需要加 \
表达转义
raw字串:原始字符串对内容不解释转义,就表达内容原本意义
import re
In [3]: re.findall('\\$\\d+','$10')
Out[3]: ['$10']
In [3]: re.findall(r'\$\d+','$10')
Out[3]: ['$10']
贪婪与非贪婪
贪婪
正则表达式的重复匹配总是尽可能多的向后匹配更多内容
import re
In [6]: re.findall(r'ab*','abbbbbb')
Out[6]: ['abbbbbb']
In [7]: re.findall(r'ab+','abbbbbb')
Out[7]: ['abbbbbb']
In [8]: re.findall(r'ab?','abbbbbb')
Out[8]: ['ab']
In [9]: re.findall(r'ab{3,5}','abbbbbb')
Out[9]: ['abbbbb']
非贪婪
正则表达式的重复匹配总是尽可能少的匹配内容
import re
In [10]: re.findall(r'ab*?','abbbbbb')
Out[10]: ['a']
In [11]: re.findall(r'ab+?','abbbbbb')
Out[11]: ['ab']
In [12]: re.findall(r'ab??','abbbbbb')
Out[12]: ['a']
In [13]: re.findall(r'ab{3,5}?','abbbbbb')
Out[13]: ['abbb']
正则表达式的子组
- 可以使用
()
为正则表达式建立子组,子组可以看做是正则表达式内部操作的一个整体 - 子组是在正则表达式整体匹配到内容的前提下才会发挥作用,它不影响正则表达式整体去匹配目标内容这一原则
子组所用
- 作为内部整体可以改变某些元字符的行为
import re
In [15]: re.search(r'(ab)*','ababab').group()
Out[15]: 'ababab'
In [39]: re.search(r"\w+\@\w+\.(com|cn)",'[email protected]').group()
Out[39]: '[email protected]'
In [40]: re.search(r"\w+\@\w+\.(com|cn)",'[email protected]').group()
Out[40]: '[email protected]'
- 子组在某些操作中可以单独提取出匹配内容
import re
In [42]: re.search(r'(https|http|ftp)://\S+','https://www.baidu.com/').group(1)
Out[42]: 'https'
子组使用注意事项
- 一个正则表达式中可以有多个子组
- 子组一般由外到内,由左到右称之为第一 第二 第三。。。子组
- 子组不能重叠,嵌套也不宜很多
捕获组和非捕获组
可以通过组名更方便获取某组内容
格式:(?P
import re
In [3]: re.search(r'(?Pab)cdef','abcdefghi').group()
Out[3]: 'abcdef'
In [4]: re.search(r'(?Pab)cdef','abcdefghi').group('dog')
Out[4]: 'ab'
正则表达式设计原则
- 正确性,能正确匹配到目标内容
- 排他性,除了要匹配的内容,尽可能不会匹配与到其他内容
- 全面性,需要对目标的各种情况进行考虑,做到不遗漏
re模块
findall()
import re
# 功能: 使用正则表达式匹配目标字符串内容
# 参数: pattern 正则表达式
# string 目标字符串
# 返回值: 列表,列表中为匹配到的内容
re.findall(pattern, string)
compile()
# 功能:生成正则表达式对象
# 参数:pattern 正则表达式
# flags 功能标志位,丰富正则表达式的匹配功能
# 返回值:返回正则表达式对象
regex = compile(pattern,flags = 0)
# 功能:从目标字符串查找正则匹配内容
# 参数:string 目标字符串
# pos 匹配目标的起始位置
# endpos 匹配目标的终止位置
# 返回值:返回匹配到的内容
# 如果正则有子组则只返回子组对应内容
regex.findall(string,pos,endpos)
split()
# 功能:根据正则匹配内容切割字符串
# 参数:pattern string flags
# 返回值:返回列表,列表中为切割的内容
re.split(pattern,string,flags = 0)
sub()
# 功能:替换正则匹配到的目标子串部分
# 参数:pattern
# replaceStr:要替换的内容
# string
# max 最多替换几处 默认全部替换
# flags
# 返回值:返回替换后的字符串
re.sub(pattern,replaceStr,string,max,flags)
subn()
# 功能:替换正则匹配到的目标子串部分
# 参数:pattern
# replaceStr : 要替换的内容
# string
# max 最多替换几处 默认全部替换
# flags
# 返回值:返回一个元组,为实际替换了几处和替换后的字符串
re.subn(pattern,replaceStr,string,max,flags)
finditer()
# 功能:使用正则表达式匹配目标字符串
# 参数:pattern string flags
# 返回值:返回一个迭代对象,迭代到的内容是一个match对象
re.finditer(pattern,string,flags)
fullmatch()
# 功能:完全匹配目标字符串
# 参数:pattern,string,flags
# 返回值:返回匹配到的match对象
# 如果没匹配成功返回None
fullmatch(pattern,string,flags)
match()
# 功能:从开头位置匹配目标字符串
# 参数:pattern,string,flags
# 返回值:返回匹配到的match对象
# 如果没匹配成功返回None
match(pattern,string,flags)
search()
# 功能:正则表达式匹配目标字符串,只匹配第一处
# 参数:pattern,string,flags
# 返回值:返回匹配到的match对象
# 如果没匹配成功返回None
search(pattern,string,flags)
compile对象属性
-
flags
:标志位 -
pattern
:正则表达式 -
groups
:有多少子组 -
groupindex
:捕获组形成组名和序列号的字典组名为键,第几组为值
match对象属性
- 属性变量
-
pos
匹配目标字符串的开始位置 -
endpos
匹配目标字符串的结束位置 -
re
正则表达式 -
string
目标字符串 -
lastgroup
最后一组的组名 -
lastindex
最后一组是第几组
-
- 属性方法
-
span()
匹配内容的起止位置 -
start()
匹配内容的开始位置 -
end()
匹配内容的结合位置 -
group()
- 功能:获取
match
对象对应的内容 - 参数:默认为0 表示获取整个正则匹配的内容,如果为序列号或者子组名则为获取某个子组匹配的对应内容
- 返回值:返回得到的子串
- 功能:获取
-
groupdict()
获取捕获组名作为键,对应内容作为值的字典 -
groups()
获取每个子组匹配内容
-
flags参数的使用
辅助正则表达式,丰富匹配结果
re.compile
re.findall
re.search
re.match
re.finditer
re.fullmatch
re.sub
re.subn
re.split
-
I == IGNORECASE
匹配时忽略字母的大小写 -
S == DOTALL
作用于元字符.
使其可以匹配换行 -
M == MULTILINE
作用于^
,$
使其可以匹配每一行开头结尾位置 -
X == VERBOSE
可以给正则添加注释
使用多个标志位使用按位或连接,例如:flags = re.X | re.I
findall()分组
- 先按照整体匹配出来,然后再匹配
()
中的 - 如果有2个或者多个
()
,则以元组的方式取显示
import re
s = "A B C D"
p1 = re.compile("\w+\s+\w+")
print(p1.findall(s)) # ['A B', 'C D']
p2 = re.compile("(\w+)\s+\w+")
# 第1步 :['A B','C D']
# 第2步 :['A','C']
print(p2.findall(s)) # ['A', 'C']
p3 = re.compile("(\w+)\s+(\w+)")
# 第1步 :['A B','C D']
# 第2步 :[('A','B'),('C','D')]
print(p3.findall(s)) # [('A', 'B'), ('C', 'D')]