正则表达式本质上来说就是定义好的一个规则,正则表达式的匹配就是从字符串中找出符合这个规则的字符串
正则匹配时,是对字符串中的字符一个个进行匹配的,逐一判断是否满足正则表达式的规则
python提供了一个re模块,re里的一些方法可以应用正则表达式对字符串进行处理
re.findall()
对字符串进行正则表达式匹配,将能够匹配的所有结果以列表形式返回,匹配失败返回空列表
re.match()
对字符串进行正则表达式匹配,匹配从头开始,只匹配一次,将能够匹配的结果以match对象的形式返回,匹配失败返回none
re.search()
对字符串进行正则表达式匹配,匹配整个字符串,只要有一次匹配就将匹配的结果以match对象的形式返回,匹配失败返回none
re.sub()
对字符串进行正则表达式替换,首先找出所有能够匹配的结果,再将匹配到的结果用替换字符串进行替换,返回替换后的字符串
1. 直接用字符串定义正则表达式
import re
str = "python3python4java5c#6"
r = re.findall("python", str)
print(r)
结果找出所有的python
['python', 'python']
2.通过元字符定义正则表达式
import re
str = "python3python4java5c#6"
r = re.findall("\d", str)
print(r)
结果找出所有的数字
['3', '4', '5', '6']
其他类似的元字符
- \d 找出所有的数字
- \D 找出所有的非数字
- \s 找出所有的空,包括(空格, \n, \t, \r, \f)
- \S 找出所有的非空
- \w 找出所有的字母、数字、下划线
- \W 找出所有的非(字母、数字、下划线)
- . 找出所有的出\n以外的所有字符, 在正则表达式处理函数加上可选标志 re.S 后可找出包括\n的所有字符, 例如:re.findall(".", str, re.S)
[] 里的字符是一种或关系,只要能匹配到里面的任何一个规则都行。比如 [abc] 则表示只要字符串里有a或者有b或者有c都满足规则
例如:
import re
str = "python3python4java5c#6"
r = re.findall("[abc]", str)
print(r)
结果找出java里的两个a , c#里的c
['a', 'a', 'c']
所以可以用
- [A-Z] 表示所有大写字母
- [a-z] 表示所有小写字母
- [0-9] 表示所有数字
- [A-Za-z0-9_] 等价于 \w
3.限定符规定字符出现的次数
限定符是跟在字符、()、[]的后面,以表示可连续出现次数
- *表示可连续出现 0 到无数次
- +表示可连续出现 1 到无数次
- ? 表示可连续出现 0 到 1 次
- {5} 表示可连续出现 5 次
- {5,} 表示可连续出现 5 到无数次
- {5,8} 表示可连续出现 5 到 8 次
import re
str = "pytho3python4pythonn5pythonnn6"
r = re.findall("python*", str)
print(r)
结果找出pytho后出现0、1、2、3个n的所有字符
['pytho', 'python', 'pythonn', 'pythonnn']
4.定位符
定位符是规定查找字符串的边界
^ 表示必须从头开始查找
$ 表示必须从结尾开始查找
\b 表示匹配一个单词边界,例如 er\b 则可以跟 never 匹配,不能跟 perf 匹配
放在前面也是一样,例如 \bap 可以跟 apple 匹配,不能跟 captain 匹配
\B 表示不匹配一个单词边界
import re
str = "pytho3python4pythonn5pythonnn6"
r = re.findall(".*6$", str)
print(r)
结果找出以6结尾的字符串,匹配成功
['pytho3python4pythonn5pythonnn6']
如果同时使用^、$进行定界, 则锁定整个要匹配的字符串,全部要满足中间的规则,而不是其中部分满足
例如:
import re
str = "100001"
r = re.findall("^\d{3,5}$", str)
print(r)
找一个长度为3到5的数字字符串,如果^定界可以匹配到10000 ,$定界可以匹配到00001,但是 ^、$ 同时使用则匹配不到
因为锁定了整个100001字符串,其长度为6,超过了允许的最大值5
^ 放在 [] 里则不是定界的作用,而是取反的作用
例如 [^a-z] 则匹配出所有非小写字母的字符
5.贪婪与非贪婪
python 里进行正则匹配时是贪婪的,会尽可能多的进行匹配
例如:
import re
str = "100001"
r = re.findall("\d{3,5}", str)
print(r)
这个例子中要匹配一个长度为3到5的数字字符串,本来匹配100也可以满足规则,但是他会贪婪的多匹配一些,匹配出10000
要使得贪婪变为非贪婪,一旦满足规则了就完成匹配,返回匹配结果 只需要在限定符后面加上? 就行
例如:
import re
str = "100001"
r = re.findall("\d{3,5}?", str)
print(r)
这样就会尽可能少的去进行匹配
在我的理解看来,加上限定符后,其进行正则匹配时,默认会使用限定符的最大取值范围进行匹配就是贪婪模式
给限定符后加上?,则会使用限定符的最小取值范围进行匹配
例如
import re
str = "100001"
r = re.findall("00*", str)
print(r)
00* 则用最大值3进行匹配出
['0000']
而加上?后
import re
str = "100001"
r = re.findall("00*?", str)
print(r)
00*? 则用最小值0进行匹配出
['0', '0', '0', '0']
6.分组
()在正则表达式中表示分组,()里的内容相当于一个子表达式,其里面的规则是一个整体
例如:
(abc)表示的是字符串中必须有连着的这样一个abc字符串
[abc]表示的是字符串中有a或有b或有c就算满足匹配
import re
str = "JavaPythonC#PythonGo"
r = re.findall("(.*)python(.*)python(.*)", str, re.I)
print(r)
返回一个匹配结果,结果是包含3个分组的一个元组组成的列表
[('Java', 'C#', 'Go')]
使用match函数获得分组
import re
str = "JavaPythonC#PythonGo"
r = re.match("(.*)python(.*)python(.*)", str, re.I)
print(r)
print(r.group())
print(r.group(1))
print(r.group(2))
print(r.group(3))
print(r.groups())
当用match函数进行正则表达式处理字符串时,默认返回包含匹配对象的match对象
r.group()是match对象的完整匹配结果
r.group(1)是完整匹配结果的分组1
r.group(2)是完整匹配结果的分组2
r.group(3)是完整匹配结果的分组3
r.groups()是包含3个分组的一个元组
<re.Match object; span=(0, 20), match='JavaPythonC#PythonGo'>
JavaPythonC#PythonGo
Java
C#
Go
('Java', 'C#', 'Go')
7.把函数作为参数进行传递
在使用re.sub()方法进行字符串替换时,可以把一个函数作为参数传递到sub()方法中
这样就可以通过这个函数对正则匹配到的字符串进行一些处理
import re
str = "JavaPythonC#PythonGo"
def convert(value):
'''
对要匹配到的要替换的字符串进行处理,这里是给各种语言加上书名号并换行
:param value: 正则匹配到的要进行替换的字符串,类型是match对象
:return: 返回处理好的字符串
'''
matched = value.group()
return "《" + matched + "》\n"
r = re.sub("[A-Z][^A-Z]*", convert, str)
print(r)
结果
《Java》
《Python》
《C#》
《Python》
《Go》