正则表达式在python中的应用

基本语法

元字符

. 匹配除换行符外任意一个字符
[a-z] 一个字母字符
[^a-z] 一个非字母字符
[0-9] 一个数字字符
[^0-9] 一个非数字字符
\b 匹配单词的边界 \bb 在文本中找到单词中b开头的b字符
\B 不匹配单词的边界 t\B 包含t的单词但是不以t结尾的t字符,例如write
\Bb不以b开头的含有b的单词,例如able
\d [0-9]匹配1位数字
\D [^0-9]匹配1位非数字
\s 匹配1位空白字符,包括换行符、制表符、空格
[ \f\r\n\t\v]
\S 匹配1位非空白字符
[^\f\r\n\t\v]
\w 匹配[a-zA-Z0-9_],包括中文的字
\W 匹配\w之外的字符
[^a-zA-Z0-9_]

转义

凡是在正则表达式中有特殊意义的符号,如果想使用它的本意,请使用\转义。反斜杠自身,得使用\\

\r\n还是转义后代表回车、换行

重复

* 表示前面的正则表达式会重复0次或多次 e\w* 单词中e后面可以有非空白字符
+ 表示前面的正则表达式重复至少1次 e\w+ 单词中e后面至少有一个非空白字符
? 表示前面的正则表达式会重复0次或1次 e\w? 单词中e后面至多有一个非空白字符
{n} 重复固定的n次 e\w{1} 单词中e后面只能有一个非空白字符
{n,} 重复至少n次 e\w{1,} 等价 e\w+
e\w{0,} 等价 e\w*
e\w{0,1} 等价 e\w?
{n,m} 重复n到m次 e\w{1,10} 单词中e后面至少1个,至多10个非空白字符

代码 说明
x|y 匹配x或者y wood took foot food
使用 w|food 或者 (w|f)ood

捕获

(pattern) 使用小括号指定一个子表达式,也叫分组捕获后会自动分配组号从1开始可以改变优先级
\数字 匹配对应的分组 \1\2
(?:pattern) 如果仅仅为了改变优先级,就不需要捕获分组 `(?:w
(?<name>exp)(?'name'exp) 命名分组捕获,但是可以通过name访问分组Python语法必须是(?P<name>exp)

断言

零宽断言

测试字符串为wood took foot food

(?=exp) 零宽度正预测先行断言断言exp一定在匹配的右边出现,也就是说断言后面一定跟个exp f(?=oo) f后面一定有oo出现,匹配的是f,oo是作为判断条件,不出现在匹配后的结果中
(?<=exp) 零宽度正回顾后发断言断言exp一定出现在匹配的左边出现,也就是说前面一定有个exp前缀 (?<=f)ood(?<=t)ook分别匹配ood、ook,ook前一定有t出现,匹配的是ood和ook,f和t是判断条件,不出现在匹配结果中

负向零宽断言

(?!exp) 零宽度负预测先行断言断言exp一定不会出现在右侧,也就是说断言后面一定不是exp \d{3}(?!\d)匹配3位数字,断言3位数字后面一定不能是数字
foo(?!d) foo后面一定不是d
(?<!exp) 零宽度负回顾后发断言断言exp一定不能出现在左侧,也就是说断言前面一定不能是exp (?<!f)ood ood的左边一定不是f

注意:

​ 断言不会捕获

​ 断言不占分组号

​ 断言如同条件,只是要求匹配必须满足断言的条件。

​ 分组和捕获是同一个意思。

​ 使用正则表达式时,能用简单表达式,就不要复杂的表达式

贪婪与非贪婪

默认是贪婪模式,也就是说尽量多匹配更长的字符串。

非贪婪很简单,在重复的符号后面加上一个?问号,就尽量的少匹配了。

*? 匹配任意次,但尽可能少重复
+? 匹配至少1次,,但尽可能少重复
?? 匹配0次或1次,,但尽可能少重复
{n,}? 匹配至少n次,但尽可能少重复
{n,m}? 匹配至少n次,至多m次,但尽可能少重复

引擎选项

引擎 解释 flag
IgnoreCase 匹配时忽略大小写,.无法匹配换行符 re.I
re.IGNORECASE
Singleline 单行模式 . 可以匹配所有字符,包括\n re.S
re.DOTALL
Multiline 多行模式 ^ 行首、$ 行尾 re.M
re.MULTILINE

单行模式:

. 可以匹配所有字符,包括换行符

^ 表示整个字符串的开头,$整个字符串的结尾

多行模式:

. 可以匹配除了换行符之外的字符,多行不影响.点号

^ 表示行首,$行尾,只不过这里的行是每一个行

默认模式:可以看做待匹配的文本是一行,不能看做多行.点号不能匹配换行符^$表示行首和行尾,而行首行尾就是整个字符串的开头和结尾

单行模式:基本和默认模式一样,只是.点号终于可以匹配任意一个字符包括换行符,这时所有文本就是一个长长的只有一行的字符串。^就是这一行字符串的行首,$就是这一行的行尾。

多行模式:重新定义了行的概念,但不影响.点号的行为,^$还是行首行尾的意思,只不过因为多行模式可以识别换行符了。"开始"指的是\n后紧接着下一个字符;"结束"指的是\n前的字符,注意最后一行结尾可以没有\n

简单讲,单行模式只影响.点号行为,多行模式重新定义行影响了^和$

常量

re.M
re.MULTILINE
多行模式
re.S
re.DOTALL
单行模式
re.I
re.IGNORECASE
忽略大小写
re.X
re.VERBOSE
忽略表达式中的空白字符

使用| 位或运算开启多种选项

方法

编译

re.compile(pattern, flags=0)

设定flags,编译模式,返回正则表达式对象regex。

​ pattern就是正则表达式字符串

​ flags是选项。正则表达式需要被编译,为了提高效率,这些编译后的结果被保存,下次使用同样的pattern的时候,就不需要再次编译。

​ re的其它方法为了提高效率都调用了编译方法,就是为了提速

import re
regex=re.compile('',re.M|re.S)
print(regex,type(regex))
#结果
re.compile('', re.MULTILINE|re.DOTALL) <class '_sre.SRE_Pattern'>

返回的是一个表达式对象

单次匹配

match 从头开始匹配,必须是开头,不在开头即匹配不到

re.match(pattern, string, flags=0)

regex.match(string[, pos[, endpos]])

match匹配从字符串的开头匹配,regex对象match方法可以重设定开始位置和结束位置。返回match对象

import re

s = 'bottle\nbag\nbig\napple'
r = re.match('c.+', s, re.S)
print(r,type(r))
#结果  当匹配不到时,返回None
None <class 'NoneType'>

r1 = re.match('b.+', s, re.S)
print(r1,type(r1))
#结果 匹配到了返回match对象
<_sre.SRE_Match object; span=(0, 20), match='bottle\nbag\nbig\napple'> <class '_sre.SRE_Match'>

print(r1.start(),r1.end(),s[r1.start():r1.end()].encode())
#结果
0 20 b'bottle\nbag\nbig\napple'

span=(0, 20)表示匹配到的字符串的范围,左包右不包

match='bottle\nbag\nbig\napple'表示对应匹配到的字符串

也可以先编译,再调用

regex=re.compile('b.+',re.S)
print(regex.match(s))
#结果也是一样的
<_sre.SRE_Match object; span=(0, 20), match='bottle\nbag\nbig\napple'>

print(regex.match(s,7,12))
#结果 指定起始位置
<_sre.SRE_Match object; span=(7, 12), match='bag\nb'>

search 从头开始找,但不要求必须是开头

re.search(pattern, string, flags=0)

regex.search(string[, pos[, endpos]])从头搜索直到第一个匹配,regex对象search方法可以重设定开始位置和结束位置,返回match对象

import re

s = 'bottle\nbag\nbig\napple'
r1 = re.search('^b.+', s, re.M)
print(r1,type(r1))
print(r1.start(),r1.end(),s[r1.start():r1.end()].encode())
regex=re.compile('^a',re.M)
print(regex.search(s))
#结果
<_sre.SRE_Match object; span=(0, 6), match='bottle'> <class '_sre.SRE_Match'>
0 6 b'bottle'
<_sre.SRE_Match object; span=(15, 16), match='a'>

fullmatch 需要完全匹配整个字符串才能匹配到

re.fullmatch(pattern, string, flags=0)

regex.fullmatch(string[, pos[, endpos]])

整个字符串和正则表达式匹配

import re

s = 'bottle\nbag\nbig\napple'
r = re.fullmatch('b.+', s, re.S)
print(r)
#结果
<_sre.SRE_Match object; span=(0, 20), match='bottle\nbag\nbig\napple'>

全文搜索

findall 全文搜索,将所有结果返回到一个列表中

re.findall(pattern, string, flags=0)

regex.findall(string[, pos[, endpos]])

对整个字符串,从左至右匹配,返回所有匹配项的列表

r2=re.findall('b.+',s,re.M)
print(r2,type(r2))
regex=re.compile('b.+',re.M)
print(regex.findall(s))
"""#结果
['bottle', 'bag', 'big'] <class 'list'>
['bottle', 'bag', 'big']"""

finditer 返回的是迭代器

re.finditer(pattern, string, flags=0)

regex.finditer(string[, pos[, endpos]])

对整个字符串,从左至右匹配,返回所有匹配项,返回迭代器。

注意每次迭代返回的是match对象

r2=re.finditer('b.+',s,re.M)
print(r2,type(r2))
regex=re.compile('b.+',re.M)
a=regex.finditer(s)
print(a,next(a))
"""
结果
<callable_iterator object at 0x000002065E345EB8> <class 'callable_iterator'>
<callable_iterator object at 0x000002065E345D68> <_sre.SRE_Match object; span=(0, 6), match='bottle'>
"""

匹配替换

sub 搜索替换,返回新字符串

re.sub(pattern, replacement, string, count=0, flags=0)

regex.sub(replacement, string, count=0)

使用pattern对字符串string进行匹配,对匹配项使用repl替换。

replacement可以是string、bytes、function

r3=re.sub('b.+','ha',s,flags=re.S)#如果要指定模式,需要用关键字传参,因为在string后面还有个count
print(r3.encode(),type(r3))
regex=re.compile('b.+',re.S)
b=regex.sub('ha',s)
print(b.encode())
"""
结果
b'ha' <class 'str'>
b'ha'
"""

subn 返回的是新字符串和替换次数组成的元组

re.subn(pattern, replacement, string, count=0, flags=0)

regex.subn(replacement, string, count=0)

同sub返回一个元组(new_string, number_of_subs_made)

r3=re.subn('b.+','ha',s,flags=re.M)
print(r3,type(r3))
regex=re.compile('b.+',re.M)
b=regex.subn('ha',s)
print(b)
"""
结果
('ha\nha\nha\napple', 3) <class 'tuple'>
('ha\nha\nha\napple', 3)
"""

分割字符串

re.split(pattern, string, maxsplit=0, flags=0)

re.split分割字符串

import re


s1 = """
os.path.abspath(path)
normpath(join(os.getcwd(), path)).
"""
w=re.split('[\s{}\[\].()]+',s1)
print(w,type(w))
"""#结果
['', 'os', 'path', 'abspath', 'path', 'normpath', 'join', 'os', 'getcwd', ',', 'path', ''] <class 'list'>"""

分组

使用小括号的pattern捕获的数据被放到了组group中。

match、search函数可以返回match对象;findall返回字符串列表;finditer返回一个个match对象

如果pattern中使用了分组,如果有匹配的结果,会在match对象中

​ 1、使用group(N)方式返回对应分组,1到N是对应的分组,0返回整个匹配的字符串,N不写缺省为0

​ 2、如果使用了命名分组,可以使用group('name')的方式取分组

​ 3、也可以使用groups()返回所有组

​ 4、使用groupdict() 返回所有命名的分组

import re

s = 'bottle\nbag\nbig\napple'
c1=re.search('(?P<name>b.*g).*(b.+g).*',s,re.S)
print(c1,c1.groups(),c1.group().encode(),c1.group(0).encode(),sep='\n')
print(c1.group(1).encode())
print(c1.group(2).encode())
print(c1.groupdict())

"""
结果
<_sre.SRE_Match object; span=(0, 20), match='bottle\nbag\nbig\napple'>
('bottle\nbag', 'big')
b'bottle\nbag\nbig\napple'
b'bottle\nbag\nbig\napple'
b'bottle\nbag'
b'big'
{'name': 'bottle\nbag'}"""

group(0)等同于group()

groups()返回的是一个元组

posted @ 2023-01-17 22:24  厚礼蝎  阅读(19)  评论(0编辑  收藏  举报