正则表达式在python中的应用
基本语法
元字符
. | 匹配除换行符外任意一个字符 | |
---|---|---|
[a-z] | 一个字母字符 | |
[^a-z] | 一个非字母字符 | |
[0-9] | 一个数字字符 | |
[^0-9] | 一个非数字字符 | |
\b | 匹配单词的边界 | \b b 在文本中找到单词中b开头的b字符 |
\B | 不匹配单词的边界 | t\B 包含t的单词但是不以t结尾的t字符,例如write \B b不以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()返回的是一个元组
本文来自博客园,作者:厚礼蝎,转载请注明原文链接:https://www.cnblogs.com/guangdelw/p/17058831.html