本文已参与「新人创作礼」活动,一起开启掘金创作之路。
一、概念
正则表达式(Regular Expression)使用单个字符串来描述、匹配一系列符合某个规则的字符串。它是对字符串操作的一种逻辑公式,用来表达对字符串的一种过滤逻辑。
主要用途有以下三种:
- 测试字符串内的模式(数据验证)
- 替换文本
- 基于模式匹配从字符串中提取子串
特点是:
- 灵活性、逻辑性、功能性非常强大
- 可以迅速地用极简单的方式复杂控制字符串
- 对于新手比较晦涩难懂
Python默认的正则表达式模块是re模块
二、入门实例
#提取字符串文本中的电话号码子串
import re
string = '电话号码是028-12345678'
regex = '\d{3,4}-\d{6,8}'
print(re.findall(regex,string))
>>['028-12345678']
三、元字符
元字符是正则表达式的逻辑元素,定义一种元素来匹配一类具有同样属性的字符或是执行一种模式操作
常用的元字符如下表所示:
| 字符 | 描述 | |
|---|---|---|
^ | 匹配字符串的开头 | |
$ | 匹配字符串的结尾 | |
* | 匹配前一个字符或子表达式0次或多次 | |
+ | 匹配1次或多次 | |
? | 匹配0次或1次 | |
{n} | 匹配n次,n>=0 | |
{n,} | 至少匹配n次 | |
{n,m} | 匹配至少n次最大m次,0<=n<=m | |
. | 匹配除换行符\n以外的所有字符 | |
| `x | y` | 匹配x或y |
[xyz] | 字符集 | |
[^xyz] | 反向字符集 | |
[a-z] | 字符范围集 | |
\f、\n、\r、\t、\v | 空白字符:换页符、换行符、回车符、制表符、垂直制表符 | |
\b与\B | 字符边界匹配和非字符边界匹配,例如er\b匹配never的er,但不匹配verb的er | |
\d与\D | 数字匹配和非数字匹配,等效于[0-9]、[^0-9] | |
\s与\S | 空白字符匹配和非空白字符匹配,等效于[\f\n\r\t\v]、[^\f\n\r\t\v] | |
\w与\W | 单词字符和下划线匹配和非单词字符和下划线匹配,等效于[A-Za-z0-9_]、[^A-Za-z0-9_] |
当?紧跟随任何其他限定字符(*、+、?、{n}、{n,}、{n,m})之后时,是非贪心匹配。
**非贪心匹配尽可能短的字符串,而贪心匹配尽可能长的字符串。**例如字符串oooo,对于模式o+?匹配o,对于模式o+匹配oooo
四、正则表达式对象
Ⅰ、re.PatternObject
Pattern对象是一个编译好的正则表达式,必须通过re.compile()构造
re.compile()返回re.PatternObject对象
对Pattern对象可以直接进行search()和match()操作,且只需要传入待匹配的字符串
import re
print(re.compile('ac',re.I).search('bAc'))
#上下等效
print(re.search('ac','bAc',re.I))
>><re.Match object; span=(1, 3), match='Ac'>
>><re.Match object; span=(1, 3), match='Ac'>
Ⅱ、re.MatchObject
group()返回匹配到的字符串groups()返回包含所有子分组的元组start()返回匹配开始的位置end()返回匹配结束的位置span()返回一个元组包含匹配的范围
>>>import re
>>>matchObj = re.match("(\w+)(\s+)(\w+)","Isaac Newton,physicist")
>>>matchObj.group()
'Isaac Newton'
>>>matchObj.group(0)
'Isaac Newton'
>>>matchObj.group(1)
'Isaac'
>>>matchObj.group(2)
' '
>>>matchObj.groups()
('Isaac',' ','Newton')
>>>matchObj.start()
0
>>>matchObj.emd()
12
>>>matchObj.span()
(0,12)
五、re.compile()
re.compile(strPattern[,flag])将字符串形式的正则表达式编译为PatternObject,其中flag参数是匹配模式,可省略,多种匹配模式混合使用按位与操作符连接。常用的匹配模式如下:
- re.I 忽略大小写(== re.Ignorecase)
- re.M 多行匹配(== re.Multiline)
import re
pattern = re.compile("\w+",re.I)
print(pattern.match('aBc123,456'))
>><re.Match object; span=(0, 6), match='aBc123'>
六、re.match()和re.search()
re.search(pattern, string, flags=0) re.match(pattern, string, flags=0) 这两个函数都是搜索匹配,而后者只在开头检查是否匹配,search会扫描遍历整个字符串检查匹配
Python offers two different primitive operations based on regular expressions: match checks for a match only at the beginning of the string, while search checks for a match anywhere in the string (this is what Perl does by default).
import re
test = 'abcdef'
matchObj = re.search('c',test)
print(matchObj)
matchObj = re.match('c',test)
print(matchObj)
matchObj = re.match('a',test)
print(matchObj)
>>'c'
>>None
>>'a'
相比于re.match(pattern,string),使用pattern = re.compile()和pattern.compile(string)能够提前编译好模式串,节约时间
七、re.split()
re.split(pattern, string, maxsplit=0, flags=0)使用正则表达式分割字符串,返回值是使用正则表达式分割之后的字符串列表。若maxsplit非零,只会切maxsplit 次片,余下部分作为一个整体添加到列表
import re
list1 = re.split('[a-f]+','0ab3B94Cde1',2,re.I)
list2 = re.split('[a-f]+','0ab3B94Cde1',flags=re.I)
print(list1,list2)
>>['0', '3', '94Cde1']
>>['0', '3', '94', '1']
八、re.findall()
findall(string[, pos[, endpos]) | re.findall(pattern, string[, flags])从左向右扫描字符串,找到RE匹配的所有子串,并把它们作为列表返回。如果正则表达式包含一个或者多个分组,那么将返回一个分组列表,此时如果有多个分组,那么它是一个元组的列表。
import re
list1 = re.findall('\d+','acb12def34fg5,6,7')
list2 = re.findall('(\d+)(\w{2})','acb12def34fg5,6,7')
print(list1,list2)
>>['12', '34', '5', '6', '7']
>>[('12', 'de'), ('34', 'fg')]
九、re.finditer()
re.finditer(pattern, string[, flags])搜索string,返回一个顺序访问每一个匹配结果(MatchObject)的迭代器。此时如果有多个分组,那么它是一个元组列表。
import re
pattern = re.compile("\d+")
for i in pattern.finditer('ab12c3d456'):
print(i.group())
>>12
>>3
>>456
十、re.sub()和re.subn()
re.sub(pattern, repl, string, count=0, flags=0)用正则表达式进行字符串替换。返回的字符串是在字符串中用RE最左边不重复的匹配来替换。如果模式没有发现,字符将被没有改变地返回。可选参数count是模式匹配后替换的最大次数且必须是非负整数,缺省值是0表示替换所有的匹配。
import re
print(re.sub('\d+','?','abc123de45f'))
>>'abc?de?f'
re.subn(pattern, repl, string[, count])用于得到替换的次数,返回替换后的字符串和替换次数构成的元组。
import re
print(re.subn('\d+','?','abc123de45f'))
>>('abc?de?f', 2)