一、什么是正则:
1、正则表达式是一个特殊的字符序列,它能帮助你方便的检查一个字符串是否与某种模式匹配
2、re 模块也提供了与这些方法功能完全一致的函数,这些函数使用一个模式字符串做为它们的第一个参数。
总结一下,先整体了解re正则:
- pattern = re.compile("\d") 将正则表达式编译成一个Pattern规则对象
- pattern.match() 从开始位置开始往后查找,返回第一个符合规则的对象
- pattern.search() 从任何位置开始往后查找,返回第一个符合规则的对象
- pattern.findall() 所有的全部匹配,返回列表
- pattern.finditer() 所有的全部匹配,返回的是一个迭代器
- pattern.split() 分割字符串,返回列表
- pattern.sub() 替换
二、re模块
2.1match方法
2.1.1语法:pattern.match(str, start, end)
实例:
import re #导入re模块
pattern = re.compile(r'\d+') #此处加r表示不转义字符串
m = pattern.match('aaaa123bbb456')
m2 = pattern.match('aaaa123bbb456', 4,10)
print(m) # None
print(m2.group()) # 123
match在没有匹配到数据的时候返回的是 None
match匹配到数据后返回的是一个对象
2.1.2match分组匹配
import re
pattern = re.compile(r'([a-z]+) ([a-z]+)', re.I)
m = pattern.match('hello world Hello Python')
print(m.group()) # hello world
print(m.group(0)) # hello world
print(m.group(1)) # hello
print(m.group(2)) # world
三. re中的编译函数
3.1 compile方法
那么如果一个正则表达式要重复使用几千次,出于效率的考虑,我们是不是应该先把这个正则先预编译好,接下来重复使用时就不再需要编译这个步骤了,直接匹配,提高我们的效率
import re
re_telephone = re.compile(r'^(\d{3})-(\d{3,8})$') # 编译
A = re_telephone.match('010-12345').groups() # 使用
print(A) # 结果 ('010', '12345')
B = re_telephone.match('010-8086').groups() # 使用
print(B) # 结果 ('010', '8086')
编译后生成Regular Expression对象,由于该对象自己包含了正则表达式,所以调用对应的方法时不用给出正则字符串。
3.2 search方法
re.search()方法扫描整个字符串,并返回第一个成功的匹配。如果匹配失败,则返回None。
与re.match()方法不同,re.match()方法要求必须从字符串的开头进行匹配,如果字符串的开头不匹配,整个匹配就失败了;
re.search()并不要求必须从字符串的开头进行匹配,也就是说,正则表达式可以是字符串的一部分
语法:re.search(pattern, string, flags=0)
- pattern : 正则中的模式字符串。
- string : 要被查找替换的原始字符串。
- flags : 标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。
例1:
import re
content = 'Hello 123456789 Word_This is just a test 666 Test'
result = re.search('(\d+).*?(\d+).*', content)
print(result)
print(result.group()) # print(result.group(0)) 同样效果字符串
print(result.groups())
print(result.group(1))
运行结果:
<_sre.SRE_Match object; span=(6, 49), match='123456789 Word_This is just a test 666 Test'>
123456789 Word_This is just a test 666 Test
('123456789', '666')
123456789
666
Process finished with exit code 0
例2:只匹配数字
import re
content = 'Hello 123456789 Word_This is just a test 666 Test'
result = re.search('(\d+)', content)
print(result)
print(result.group()) # print(result.group(0)) 同样效果字符串
print(result.groups())
运行结果:
<_sre.SRE_Match object; span=(6, 15), match='123456789'>
123456789
('123456789',)
123456789
Process finished with exit code 0
3.3 finall方法
返回一个包含所有匹配到的字符串的列表。
- pattern 匹配模式,由 re.compile 获得
- string 需要匹配的字符串
import re
str = 'say hello world! hello python'
pattern = re.compile(r'(?P<first>h\w)(?P<symbol>l+)(?P<last>o\s)') # 分组,0 组是整个 world!, 1组 or,2组 ld!
match = re.findall(pattern, str)
print(match)
运行结果:
[('he', 'll', 'o '), ('he', 'll', 'o ')]
另外,多讲两个名字类似的:
re.finditer :re.finditer(pattern, string[, flags=0])
re.findall:re.findall(pattern, string[, flags=0])
- pattern compile 生成的正则表达式对象,或者自定义也可
- string 要匹配的字符串
findall 返回一个包含所有匹配到的字符的列表,列表类以元组的形式存在。
finditer 返回一个可迭代对象。
例1:
pattern = re.compile(r'\d+@\w+.com') #通过 re.compile 获得一个正则表达式对象
result_finditer = re.finditer(pattern, content)
print(type(result_finditer))
print(result_finditer) # finditer 得到的结果是个可迭代对象
for i in result_finditer: # i 本身也是可迭代对象,所以下面要使用 i.group()
print(i.group())
result_findall = re.findall(pattern, content)
print(type(result_findall)) # findall 得到的是一个列表
print(result_findall)
for p in result_finditer:
print(p)
运行结果:
<class 'callable_iterator'>
<callable_iterator object at 0x10545ec88>
123456@163.com
234567@163.com
345678@163.com
<class 'list'>
['123456@163.com', '234567@163.com', '345678@163.com']
由结果可知:finditer 得到的是可迭代对象,finfdall 得到的是一个列表
例2:
import re
content = '''email:123456@163.com
email:234567@163.com
email:345678@163.com
'''
pattern = re.compile(r'(?P<number>\d+)@(?P<mail_type>\w+).com')
result_finditer = re.finditer(pattern, content)
print(type(result_finditer))
print(result_finditer)
iter_dict = {} # 把最后得到的结果
for i in result_finditer:
print('邮箱号码是:', i.group(1),'邮箱类型是:',i.group(2))
number = i.group(1)
mail_type = i.group(2)
iter_dict.setdefault(number, mail_type) # 使用 dict.setdefault 创建了一个字典
print(iter_dict)
print('+++++++++++++++++++++++++++++++')
result_findall = re.findall(pattern, content)
print(result_findall)
print(type(result_findall))
运行结果:
<class 'callable_iterator'>
<callable_iterator object at 0x104c5cbe0>
邮箱号码是: 123456 邮箱类型是: 163
邮箱号码是: 234567 邮箱类型是: 163
邮箱号码是: 345678 邮箱类型是: 163
{'123456': '163', '234567': '163', '345678': '163'}
+++++++++++++++++++++++++++++++
[('123456', '163'), ('234567', '163'), ('345678', '163')]
<class 'list'>
finditer 得到的可迭代对象 i,也可以使用 lastindex,lastgroup 方法。
print('lastgroup 最后一个被捕获的分组的名字',i.lastgroup)
findall 当正则没有分组,返回就是正则匹配。
e.findall(r"\d+@\w+.com", content)
['2345678@163.com', '2345678@163.com', '345678@163.com']
有一个分组返回的是分组的匹配
re.findall(r"(\d+)@\w+.com", content)
['2345678', '2345678', '345678']
多个分组时,将结果作为 元组,一并存入到 列表中。
re.findall(r"(\d+)@(\w+).com", content)
[('2345678', '163'), ('2345678', '163'), ('345678', '163')]
小结:search找到就返回,finall全部找到才返回
3.5 split方法
split能够按照所能匹配的字串将字符串进行切分,返回切分后的字符串列表
语法:re.split(pattern, string[, maxsplit=0, flags=0])
pattern:匹配的字符串
string:需要切分的字符串
maxsplit:分隔次数,默认为0(即不限次数)
flags:标志位,用于控制正则表达式的匹配方式,比如:是否区分大小写
import re
line = 'aaa bbb ccc;ddd eee,fff'
print(line)
'aaa bbb ccc;ddd eee,fff'
单字符切割
re.split(r';',line)
结果:
['aaa bbb ccc', 'ddd\teee,fff']
两个字符以上切割需要放在 [ ] 中
re.split(r'[;,]',line)
结果:
['aaa bbb ccc', 'ddd\teee', 'fff']
所有空白字符切割
re.split(r'([;])',line)
结果:
['aaa bbb ccc', ';', 'ddd\teee,fff']
不想保留分隔符,以(?:...)的形式指定
re.split(r'(?:[;])',line)
结果:
['aaa bbb ccc', 'ddd\teee,fff']
四. 贪婪模式与非贪婪模式
正则表达式通常用于在文本中查找匹配的字符串。
Python里数量词默认是贪婪的(在少数语言里也可能是默认非贪婪),总是尝试匹配尽可能多的字符;
非贪婪则相反,总是尝试匹配尽可能少的字符。在"*","?","+","{m,n}"后面加上?,使贪婪变成非贪婪
总结一下:
- 贪婪:在满足条件情况下尽可能匹配到数据
- 非贪婪:满足条件就可以,在
"*","?","+","{m,n}"
后面加上?
,就能将贪婪变成非贪婪.
import re
# 贪婪匹配
greedy_pattern = re.compile(r'ab.*c')
greedy_match = greedy_pattern.match('abcaxc')
print("贪婪匹配结果:" + greedy_match.group())
# 非贪婪匹配
not_greedy_pattern = re.compile(r'ab.*?c')
not_greedy_match = not_greedy_pattern.match('abcaxc')
print("非贪婪匹配结果:" + not_greedy_match.group())
输出:
贪婪匹配结果:abcaxc
非贪婪匹配结果:abc