一、写作初衷
正则表达式,有木有人像我一样,学了不知道多少遍,学的时候看起来都懂了,过一段时间就又忘的差不多了,等真正要用到的时候,还是一脸懵逼。说到底还是练习的不够多,一直处于只看不做的程度上。所以搜集了这些正则习题,一来保证温故而知新,二来为面试做准备。
二、基本匹配规则
三、基本知识普及
3.1贪婪与非贪婪
正则表达式通常用于在文本中查找匹配的字符串。Python里默认是采用贪婪,总是尝试匹配尽可能多的字符;非贪婪的则相反,总是尝试匹配尽可能少的字符。例如:正则表达式"ab*“如果用于查找"abbbc”,将找到"abbb"。而如果使用非贪婪的数量词"ab*",将找到"a"。
3.2转义问题
正则表达式中用“\”表示转义,而python中也用“\”表示转义,当遇到特殊字符需要转义时,你要花费心思到底需要几个“\”,所以为了避免这个情况,墙裂推荐使用原生字符串类型(raw string)来书写正则表达式。
方法很简单,只需要在表达式前面加个“r”即可,如下
r'\d{2}-\d{8}'
r'\bt\w*\b'
3.3 匹配模式
正则表达式提供了一些可用的匹配模式,比如忽略大小写、多行匹配等,这部分内容将在Pattern类的工厂方法re.compile(pattern[, flags])中一起介绍。
四、re模块介绍
Python通过re模块提供对正则表达式的支持。使用re的一般步骤是先将正则表达式的字符串形式编译为Pattern实例,然后使用Pattern实例处理文本并获得匹配结果(一个Match实例),最后使用Match实例获得信息,进行其他的操作。
import re
# 将正则表达式编译成Pattern对象
pattern = re.compile(r'hello')
# 使用Pattern匹配文本,获得匹配结果,无法匹配时将返回None
match = pattern.match('hello world!')
if match:
# 使用Match获得分组信息
print(match.group())
else:
print('None')
### 输出 ###
# hello
re.compile(strPattern[, flag]):
这个方法是Pattern类的工厂方法,用于将字符串形式的正则表达式编译为Pattern对象。 第二个参数flag是匹配模式,取值可以使用按位或运算符’|‘表示同时生效,比如re.I | re.M。另外,你也可以在regex字符串中指定模式,比如re.compile(‘pattern’, re.I | re.M)与re.compile(’(?im)pattern’)是等价的。
可选值有:
Match
Match对象是一次匹配的结果,包含了很多关于此次匹配的信息,可以使用Match提供的可读属性或方法来获取这些信息。
属性:
string: 匹配时使用的文本。
re: 匹配时使用的Pattern对象。
pos: 文本中正则表达式开始搜索的索引。值与Pattern.match()和Pattern.seach()方法的同名参数相同。
endpos: 文本中正则表达式结束搜索的索引。值与Pattern.match()和Pattern.seach()方法的同名参数相同。
lastindex: 最后一个被捕获的分组在文本中的索引。如果没有被捕获的分组,将为None。
lastgroup: 最后一个被捕获的分组的别名。如果这个分组没有别名或者没有被捕获的分组,将为None。
方法:
group([group1, …]):
获得一个或多个分组截获的字符串;指定多个参数时将以元组形式返回。group1可以使用编号也可以使用别名;编号0代表整个匹配的子串;不填写参数时,返回group(0);没有截获字符串的组返回None;截获了多次的组返回最后一次截获的子串。
groups([default]):
以元组形式返回全部分组截获的字符串。相当于调用group(1,2,…last)。default表示没有截获字符串的组以这个值替代,默认为None。
groupdict([default]):
返回以有别名的组的别名为键、以该组截获的子串为值的字典,没有别名的组不包含在内。default含义同上。
start([group]):
返回指定的组截获的子串在string中的起始索引(子串第一个字符的索引)。group默认值为0。
end([group]):
返回指定的组截获的子串在string中的结束索引(子串最后一个字符的索引+1)。group默认值为0。
span([group]):
返回(start(group), end(group))。
4.1 re常用功能函数
4.1.1 re.match()
从字符串的起始位置匹配,匹配成功,返回一个匹配的对象,否则返回None
语法:re.match(pattern, string, flags=0)
pattern:匹配的正则表达式
string:要匹配的字符串
flags:标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等;flags=0表示不进行特殊指定
不含标志位:
>>> re.match(r'\d{2}','123')
<_sre.SRE_Match object; span=(0, 2), match='12'>
>>> re.match(r'\d{2}','ab123')
>>> print(re.match(r'\d{2}','ab123'))
None
含有标志位:
>>> re.match(r'a','ab123').group()
'a'
>>> re.match(r'a','Ab123').group()
Traceback (most recent call last):
File "<pyshell#5>", line 1, in <module>
re.match(r'a','Ab123').group()
AttributeError: 'NoneType' object has no attribute 'group'
>>> re.match(r'a','Ab123',re.I).group()
'A'
4.1.2 re.search()
扫描整个字符串并返回第一个成功的匹配对象,否则返回None
语法:re.search(pattern, string, flags=0)
>>> re.search(r'\d{2}','Ab123')
<_sre.SRE_Match object; span=(2, 4), match='12'>
>>> re.search(r'\d{2}','Abcde')
>>> print(re.search(r'\d{2}','Abcde'))
None
可以看到match()和search()返回的时match对象(即匹配对象),可以通过group()方法获得匹配内容
>>> re.search(r'\d{2}','Ab12c34d56e78').group()
'12'
>>> re.match(r'\d{2}','12c34d56e78').group(0)
'12'group() 同group(0)就是匹配正则表达式整体结果,也就是所有匹配到的字符
group()其实更多的结合分组来使用,即如果在正则表达式中定义了分组(什么是分组?参见正则表达式学习,一个左括号“(”,表示一个分组),就可以在match对象上用group()方法提取出子串来。后面会单独写一下group()和groups()的用法,这里先简单了解一下。
4.1.3 re.findall()
在字符串中找到正则表达式所匹配的所有子串,并返回一个列表,如果没有找到匹配的,则返回空列表
注意: match 和 search 是匹配一次,而findall 匹配所有
>>> re.findall(r'\d{2}','21c34d56e78')
['21', '34', '56', '78']
4.1.4 re.finditer()
和 findall 类似,在字符串中找到正则表达式所匹配的所有子串,并把它们作为一个迭代器返回.
>>> match = re.finditer(r'\d{2}','21c34d56e78')
>>> for t in match:
print(t.group())
21
34
56
78
>>>
4.1.5 re.split()
根据正则表达式中的分隔符把字符分割为一个列表并返回成功匹配的列表.
>>> match = re.split(r'\.|-','hello-world.data') # 使用 . 或 - 作为字符串的分隔符
>>> print(match)
['hello', 'world', 'data']
字符串也有split方法,如下,作个对比:
字符串的split方法
>>> 'a b c'.split(' ') # b和c之间有3个空格
['a', 'b', '', '', 'c']
如果用空格不好理解的话,可以换位x
>>> 'axbxxxc'.split('x')
['a', 'b', '', '', 'c']
>>>
可以看到,单纯用字符串的split方法无法识别连续的空格,
用正则表示式如下:
>>> re.split(r'\s+', 'a b c') # \s+ 表示匹配一个或多个空白符(\s表示匹配空白符,+表示重复1次或1次以上)
['a', 'b', 'c']
>>>
4.1.6 re.sub()
用于替换字符串中的匹配项
语法: re.sub(pattern, repl, string, count=0)
- pattern : 正则中的模式字符串。
- repl : 替换的字符串,也可为一个函数。 string : 要被查找替换的原始字符串。
- count : 模式匹配后替换的最大次数,默认 0 表示替换所有的匹配。
>>> match = re.sub(r'a', 'b','aaccaa') # 把字符串中的a都替换为b
>>> print(match)
bbccbb
>>>
五、re常见面试题
5.1 re.match与re.search的区别?
re.match只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回None;而re.search匹配整个字符串,直到找到一个匹配(注意:仅仅是第一个)
5.2 再python中group和groups的区别
答:group和groups是两个不同的函数。
一般,m.group(N) 返回第N组括号匹配的字符。
而m.group() == m.group(0) == 所有匹配的字符,与括号无关,这个是API规定的。
m.groups() 返回所有括号匹配的字符,以tuple格式(元组格式),不包括
m.group(0),即整个表达式.
m.groups() == (m.group(0), m.group(1),……)
5.3 python正则表达式中“.”和“.?”的区别
答:表达式 .* 的意思很好理解,就是单个字符匹配任意次,即贪婪匹配。
表达式 .*? 是满足条件的情况只匹配一次,即懒惰匹配