一、什么是正则:
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模块
<p>pattern = re.compile(r'\d+') #此处加r表示不转义字符串</p>
<p>m = pattern.match('aaaa123bbb456')</p>
<p>m2 = pattern.match('aaaa123bbb456', 4,10)</p>
<p>print(m) # None</p>
print(m2.group()) # 123
match在没有匹配到数据的时候返回的是 None
match匹配到数据后返回的是一个对象
2.1.2match分组匹配 import re
<p>pattern = re.compile(r'([a-z]+) ([a-z]+)', re.I)</p>
<p>m = pattern.match('hello world Hello Python')</p>
<p>print(m.group()) # hello world</p>
<p>print(m.group(0)) # hello world</p>
<p>print(m.group(1)) # hello</p>
print(m.group(2)) # world
三. re中的编译函数
3.1 compile方法
那么如果一个正则表达式要重复使用几千次,出于效率的考虑,我们是不是应该先把这个正则先预编译好,接下来重复使用时就不再需要编译这个步骤了,直接匹配,提高我们的效率import re
<p>re_telephone = re.compile(r'^(\d{3})-(\d{3,8})$') # 编译</p>
<p>A = re_telephone.match('010-12345').groups() # 使用</p>
<p>print(A) # 结果 ('010', '12345')</p>
<p>B = re_telephone.match('010-8086').groups() # 使用</p>
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
<p>content = 'Hello 123456789 Word_This is just a test 666 Test'</p>
<p>result = re.search('(\d+).<em>?(\d+).</em>', content)</p>
<p>print(result)</p>
<p>print(result.group()) # print(result.group(0)) 同样效果字符串</p>
<p>print(result.groups())</p>
print(result.group(1))
运行结果:<_sre.SRE_Match object; span=(6, 49), match='123456789 Word_This is just a test 666 Test'>
<p>123456789 Word_This is just a test 666 Test</p>
<p>('123456789', '666')</p>
<p>123456789</p>
<p>666</p>
Process finished with exit code 0
例2:只匹配数字import re
<p>content = 'Hello 123456789 Word_This is just a test 666 Test'</p>
<p>result = re.search('(\d+)', content)</p>
<p>print(result)</p>
<p>print(result.group()) # print(result.group(0)) 同样效果字符串</p>
<p>print(result.groups())</p>
运行结果:<_sre.SRE_Match object; span=(6, 15), match='123456789'>
<p>123456789</p>
<p>('123456789',)</p>
<p>123456789</p>
<p>Process finished with exit code 0</p>
3.3 finall方法
返回一个包含所有匹配到的字符串的列表。
pattern 匹配模式,由 re.compile 获得
string 需要匹配的字符串
import re
<p>str = 'say hello world! hello python'</p>
<p>pattern = re.compile(r'(?P<first>h\w)(?P<symbol>l+)(?P<last>o\s)') # 分组,0 组是整个 world!, 1组 or,2组 ld!</p>
<p>match = re.findall(pattern, str)</p>
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 获得一个正则表达式对象
<p>result_finditer = re.finditer(pattern, content)</p>
<p>print(type(result_finditer))</p>
<p>print(result_finditer) # finditer 得到的结果是个可迭代对象</p>
<p>for i in result_finditer: # i 本身也是可迭代对象,所以下面要使用 i.group()</p>
<p>print(i.group())</p>
<p>result_findall = re.findall(pattern, content)</p>
<p>print(type(result_findall)) # findall 得到的是一个列表</p>
<p>print(result_findall)</p>
<p>for p in result_finditer:</p>
print(p)
运行结果:<class 'callable_iterator'>
<p><callable_iterator object at 0x10545ec88></p>
<p>123456@163.com</p>
<p>234567@163.com</p>
<p>345678@163.com</p>
<p><class 'list'></p>
['123456@163.com', '234567@163.com', '345678@163.com']
由结果可知:finditer 得到的是可迭代对象,finfdall 得到的是一个列表 例2: import re
<p>content = '''email:123456@163.com</p>
<p>email:234567@163.com</p>
<p>email:345678@163.com</p>
<p>'''</p>
<p>pattern = re.compile(r'(?P<number>\d+)@(?P<mail_type>\w+).com')</p>
<p>result_finditer = re.finditer(pattern, content)</p>
<p>print(type(result_finditer))</p>
<p>print(result_finditer)</p>
<p>iter_dict = {} # 把最后得到的结果</p>
<p>for i in result_finditer:</p>
<p>print('邮箱号码是:', i.group(1),'邮箱类型是:',i.group(2))</p>
<p>number = i.group(1)</p>
<p>mail_type = i.group(2)</p>
<p>iter_dict.setdefault(number, mail_type) # 使用 dict.setdefault 创建了一个字典</p>
<p>print(iter_dict)</p>
<p>print('+++++++++++++++++++++++++++++++')</p>
<p>result_findall = re.findall(pattern, content)</p>
<p>print(result_findall)</p>
print(type(result_findall))
运行结果:<class 'callable_iterator'>
<p><callable_iterator object at 0x104c5cbe0></p>
<p>邮箱号码是: 123456 邮箱类型是: 163</p>
<p>邮箱号码是: 234567 邮箱类型是: 163</p>
<p>邮箱号码是: 345678 邮箱类型是: 163</p>
<p>{'123456': '163', '234567': '163', '345678': '163'}</p>
<p>+++++++++++++++++++++++++++++++</p>
<p>[('123456', '163'), ('234567', '163'), ('345678', '163')]</p>
<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
<p>line = 'aaa bbb ccc;ddd eee,fff'</p>
<p>print(line)</p>
'aaa bbb ccc;ddd eee,fff'
单字符切割re.split(r';',line)
<p>结果:</p>
['aaa bbb ccc', 'ddd\teee,fff']
两个字符以上切割需要放在 [ ] 中re.split(r'[;,]',line)
<p>结果:</p>
['aaa bbb ccc', 'ddd\teee', 'fff']
所有空白字符切割re.split(r'([;])',line)
<p>结果:</p>
['aaa bbb ccc', ';', 'ddd\teee,fff']
不想保留分隔符,以(?:...)的形式指定re.split(r'(?:[;])',line)
<p>结果:</p>
['aaa bbb ccc', 'ddd\teee,fff']
四. 贪婪模式与非贪婪模式
正则表达式通常用于在文本中查找匹配的字符串。
Python里数量词默认是贪婪的(在少数语言里也可能是默认非贪婪),总是尝试匹配尽可能多的字符;
非贪婪则相反,总是尝试匹配尽可能少的字符。在"*","?","+","{m,n}"后面加上?,使贪婪变成非贪婪
总结一下:
贪婪:在满足条件情况下尽可能匹配到数据
非贪婪:满足条件就可以,在"<em>","?","+","{m,n}"后面加上?,就能将贪婪变成非贪婪.
import re
<br><h1>贪婪匹配</h1><br>
<p>greedy_pattern = re.compile(r'ab.</em>c')</p>
<p>greedy_match = greedy_pattern.match('abcaxc')</p>
<p>print("贪婪匹配结果:" + greedy_match.group())</p>
<br><h1>非贪婪匹配</h1><br>
<p>not_greedy_pattern = re.compile(r'ab.*?c')</p>
<p>not_greedy_match = not_greedy_pattern.match('abcaxc')</p>
print("非贪婪匹配结果:" + not_greedy_match.group())
输出:贪婪匹配结果:abcaxc
非贪婪匹配结果:abc