Python——正则表达式
什么是正则表达式
正则表达式(简称regex)是一些由字符和特殊符号组成的字符串,可以给匹配、抽取、替换字符串带来极大的方便。python通过标准库中的re模块来支持正则表达式。
特殊符号和字符
1 择一匹配(’|’)
表示从多个模式中选择其一。下表左边是运用择一匹配的模式,右边是能够匹配到的字符串。
正则表达式模式 | 匹配的字符串 |
---|---|
at|home | at、home |
r2d2|c3po | r2d2、c3po |
bat|bet | \bit |
2 匹配任意单个字符
点号(’.’)能够匹配除了换行符\n以外的任何单个字符
3 从字符串起始或者结尾或者单词边界匹配
表示法 | 描述 | 正则表达式示例 |
---|---|---|
^(脱字符) | 匹配字符串起始部分 | ^Dear, Dear必须出现在字符串开头,例如MyDear就不行 |
$(美元符号) | 匹配字符串终止部分 | bin$ |
\b | 匹配一个单词的边界 | \bthe, 以the开始的字符串,\bthe\b, 仅仅匹配单词the |
\B | 与\b相反 | \Bthe, 包含但并不以the作为起始的字符串 |
脱字符(^)和美元符号($)是匹配整个字符串的起始和终止位置,而\b是匹配单词边界起始或者终止部分。
4 字符集
有些时候,可能想匹配某些特定字符,例如元音字母。正因如此发明了方括号[],该正则表达式能够匹配一对方括号中包含的任何字符。
正则表达式 | 匹配的字符串 |
---|---|
b[aeiu]t | bat、bet、bit、but |
[cr][23][dp][o2] | c2do、c2d2、c2po、c2p2等 |
高级用法
Ⅰ、在方括号内使用连字符(’-’)可以指定一个字符范围,不用全部都写出来。
[a-z] 表示26个小写字母,非常的方便,类似的还有[1-19]、[A-Z]等
Ⅱ、脱字符(^)紧跟在左方括号后面表示匹配方括号以外的字符
[^aeiou],匹配非元音字符。
Ⅲ、表示字符集的特殊字符
特殊字符 | 描述 |
---|---|
\d | 匹配任何十进制数字,与[0-9]一致 |
\D | 与\d相反,[^0-9] |
\w | 匹配任何字母数字字符,与[0-9a-zA-Z_]相同 |
\W | 与\w相反 |
\s | 匹配任何空格字符 |
\S | 与\s相反 |
5 圆括号分组
我们不仅想要知道整个字符串是否匹配我们的标准,而且想要知道能否提取任何已经成功匹配的特定字符串或者子字符串。
要实现这个目标,只要用一对圆括号包裹需要提取部分的正则表达式即可。
圆括号的功能:
- 对正则表达式进行分组(可在正则表达式中使用重复操作符)
- 匹配子组
匹配模式的子字符串可以保存起来供后续使用,如果不想这样,可使用(?: )的形式。
例如(\w+)-(\d+),然后就能够分别访问每一个匹配子组。
6 扩展表示法
扩展表示法 | 描述 |
---|---|
(?iLmsux) | 在正则表达式中嵌入的一个或者多个标记参数 |
(?:…) | 表示一个匹配不用保存的分组 |
(?P…) | 仅由name标识而不是数字ID标识的正则分组匹配 |
(?P=name) | 在同一字符串中匹配由(?P)分组的之前文本 |
(?#…) | 注释,被忽略 |
(?=…) | 匹配条件是如果…出现在之后的位置,不使用输入字符串,称作正向前视断言 |
(?!..) | 匹配条件是如果…不出现在之后的位置,不使用输入字符串,称作负向前视断言 |
(?<=…) | 匹配条件是如果…出现在之前的位置,不使用输入字符串,称作正向后视断言 |
(?<!..) | 匹配条件是如果…不出现在之前的位置,不使用输入字符串,称作负向后视断言 |
(?(id/name)Y|N) | 分组所提供的id或者name存在,就返回正则表达式的条件匹配Y,如果不存在,就返回N;|N是可选项 |
7 存在性和频数匹配
符号 | 描述 |
---|---|
* | 匹配前面的正则表达式任意次(包括零次) |
+ | 至少匹配前面的正则表达式一次 |
? | 匹配前面的正则表达式零次或者一次 |
{N} | 匹配前面的正则表达式N次 |
{M, N} | 匹配前面的正则表达式M~N次 |
{N, } | 匹配前面的正则表达式大于等于N次 |
正则表达式和Python语言
正则表达式对象(regex object)
正则匹配对象(regex match object)
常用的函数方法介绍
1 match() search() compile()
match(pattern, string, flags=0)
search(pattern, string, flags=0),只返回第一次成功匹配的对象
compile(pattern, flags=0),使用任何可选的标记来编译正则表达式的模式,返回一个正则表达式对象,非必须,但使用预编译可提升执行性能
如果匹配成功,就返回匹配对象,如果失败,就返回Nnoe
区别:match从字符串起始部分匹配,search从整个字符串中查找
import re
# 匹配失败
m1 = re.match('foo', 'seafood')
# 匹配成功
m2 = re.search('foo', 'seafood')
匹配对象有两个主要的方法:group()、groups()
group()要么返回整个匹配对象,要么根据要求返回特定子组。
groups()仅返回一个包含唯一或者全部子组的元组。
注意:如果没有子组的要求,那么当group()仍然返回整个匹配时,groups()返回一个空元组。None是返回的错误值,该值没有group()和groups()方法,会出现AttributeError异常,保险的使用方式是加上一个if判断
if m is not None: print(m.group())
一些简单示例
>>>m = re.match('ab', 'ab')
>>>m.group()
'ab'
>>>m.groups()
()
>>>
>>>m = re.match('(ab)', ab)
>>>m.group()
'ab'
>>>m.group(1)
'ab'
>>>m.groups()
('ab', )
2 findall() finditer()
findall()返回所有成功匹配的列表;
finditer()返回一个迭代器
import re
s = 'This and That.'
print(re.findall(r'(th\w+)', s, re.I))
m = [g.group(1) for g in re.finditer(r'(th\w+)', s, re.I)]
print(m)
['This', 'That']
['This', 'That']
3 sub() subn()
两者几乎一样,都是将某字符串中所有匹配正则表达式的部分进行某种形式的替换,区别是subn()还返回一个表示替换的总数,替换后的字符串和表示替换总数的数字一起作为一个拥有两个元素的元组返回。
print(re.sub('X', 'Mr. Smith', 'attn: X\nDear X,\n'))
print(re.subn('X', 'Mr. Smith', 'attn: X\nDear X,\n'))
attn: Mr. Smith
Dear Mr. Smith,
('attn: Mr. Smith\nDear Mr. Smith,\n', 2)
4 分割字符串
import re
Data = (
'Mountain View, CA 94040',
'Sunnyvale, CA',
'Los Altos, 94023',
'Cupertino 95014',
'Palo Alto CA',
)
for datum in Data:
print(re.split(r', | (?=\d{5}|[A-Z]{2})', datum))
['Mountain View', 'CA', '94040']
['Sunnyvale', 'CA']
['Los Altos', '94023']
['Cupertino', '95014']
['Palo Alto', 'CA']
如果有符号同时用于ASCII和正则表达式,就会出现问题,建议使用python的原始字符串来避免产生问题。
5 用于大多数正则表达式函数的标记
常用的模块属性 | 描述 |
---|---|
re.I、re.IGNORECASE | 不区分大小写的匹配 |
re.L、re.LOCALE | |
re.M、re.MULTILINE | ^和$分别匹配目标字符串行的起始和结尾,而不是严格的起始和结尾 |
re.S、re.DOTALL | 点号能够匹配全部字符 |
re.X、re.VERBOSE | 提高正则表达式的可读性 |
import re
m = re.match(r'''(?x)
\((?P<areacode>\d{3})\)[ ](?P<prefix>\d{3})-(?P<number>\d{4})
[ ]
(?P=areacode)-(?P=prefix)-(?P=number)
[ ]
1(?P=areacode)(?P=prefix)(?P=number)
''', '(800) 555-1212 800-555-1212 18005551212')
if m is not None:
print(m.groups())
('800', '555', '1212')
m = re.findall(r'(?m)^\s+(?!noreply|postmaster)(\w+)',
'''
sales@phptr.com
postmaster@phptr.com
eng@phptr.com
noreply@phptr.com
admin@phptr.com
''')
print(m)
['sales', 'eng', 'admin']