一、什么是正则:

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