一、re模块的作用
python中的re模块是跟正则表达式相关的一个模块,当你导入了re模块之后就可以进行正则匹配了。那么在说re模块的用法之前我们先要来说一下正则表达式的一些规则,不会正则有了re模块也没有用。
二、正则表达式
首先,正则表达式是干什么的呢?正则表达式就是按照你规定的一个匹配规则从给定的字符串中取出符合规则的部分。比如一个简单的正则匹配的例子如下:
1 import reView Code
2 s='alex' #待匹配的字符串
3 r='a' #你定义的匹配规则
4 print(re.search(r,s).group())
5 --------------------------------------------------------------------------------------
6 a
例子中的s变量中的值就是我们需要去匹配筛选的字符串,而变量r中的值就是我们定义的正则表达式中的匹配规则,正则表达式的匹配规则大多数就是一些元字符和量词的组合,另外就是一个.*?的用法以及re模块中findall、split模式对分组的优先级问题。
首先我们来了解一下正则表达式中的元字符有哪些,正则表达式的所有元字符如下:
元字符 |
匹配内容
|
. | 匹配除换行符以外的任意字符 |
\w | 匹配字母或数字或下划线 |
\s | 匹配任意的空白符 |
\d | 匹配数字 |
\n | 匹配一个换行符 |
\t | 匹配一个制表符 |
\b | 匹配一个单词的结尾 |
^ | 匹配字符串的开始 |
$ | 匹配字符串的结尾 |
\W | 匹配非字母或数字或下划线 |
\D | 匹配非数字 |
\S | 匹配非空白符 |
a|b | 匹配字符a或字符b |
() | 匹配括号内的表达式,也表示一个组 |
[...] | 匹配字符组中的字符 |
[^...] | 匹配除了字符组中字符的所有字符 |
然后就是正则表达式中的一些量词
量词 |
用法说明 |
* | 重复零次或更多次 |
+ | 重复一次或更多次 |
? | 重复零次或一次 |
{n} | 重复n次 |
{n,} | 重复n次或更多次 |
{n,m} | 重复n到m次 |
我们只需要记住这些元字符和量词然后进行适当的组合就能从一个字符串中匹配出我们需要的子字符串了,但是我们需要知道的是正则表达式在匹配的过程中是一种贪婪匹配的方式即正则表达式会在你指定的匹配次数范围内匹配尽可能长的字符串,那么当我们不希望以贪婪模式去匹配怎么办呢,只需要在匹配规则的量词后面加上?号就会匹配符合条件的最小的字符串。然后就是一个.*?的用法,按照之前的说法这个匹配规则就是匹配0个字符,那这有什么用呢?比如.*?x就表示匹配任意长度的任意字符直到出现x为止停止匹配。
正则表达式中还有一个分组命名的东西,(?P<id>\d+)像这样在一个分组内用?P<分组名>的形式就是在给这个分组命名了,你可以在另一个分组中用?P=分组名的方式去应用这个分组的正则表达式比如(?P=id)这样,另外你还可以在输出匹配结果是单独输出某个分组的匹配结果,比如
1 com=re.compile('<div class="item">.*?<div class="pic">.*?<em .*?>(?P<id>\d+).*?<span class="title">(?P<title>.*?)</span>'View Code
2 '.*?<span class="rating_num" .*?>(?P<rating_num>.*?)</span>.*?<span>(?P<comment_num>.*?)评价</span>',re.S)
3
4 ret=com.finditer(s)
5 for i in ret:
6 yield {
7 "id":i.group("id"), #取id分组的匹配结果
8 "title":i.group("title"), #取title分组的匹配结果
9 "rating_num":i.group("rating_num"), #取rating_num分组的匹配结果
10 "comment_num":i.group("comment_num"),
11 }
最后还有一个转义符的问题,正则表达式中存在一些具有特殊含义的字符比如\n、\t等,我们在匹配时如果想匹配这些字符本身就需要加\进行转义,然而在字符串中也存在这样的特殊字符所以也需要转义,于是在正则匹配时我们又需要对字符串中用于转义的\进行转义,因为\也是有特殊含义的,于是要匹配一个\n正则表达式就要写成\\\\n,这就显得很麻烦,当然有简单的方法就是在在匹配规则外加个r就可以取消正则表达式中特殊字符的作用让他们只表示本身,我们只需要对字符串中用于转义的\进行转义就行了,于是正则表达式就可以简化为r'\\n'。
三、re模块的匹配模式
常用模式
findall:返回值是一个列表,列表中是所有满足条件的匹配结果。这个模式是匹配字符串任意位置中满足条件的子字符串
search:返回的是第一个满足条件的匹配结果。这个模式也是匹配字符串任意位置中满足条件的子字符串
match:返回结果和search一样,但是这个模式是从字符串开头开始匹配,开头匹配不上就认为没有满足条件的子字符串
重要的模式
split:按规则对字符串进行分割,分割后作为分割的字符不显示,比如ret = re.split('[ab]', 'abcd'),先按字符a分割,再按字符b分割,结果为['', '', 'cd'],如果需要保留作为分割的字符需要在正则条件上加上括号像这样ret = re.split('([ab])', 'abcd'),结果就会变为['', 'a', '', 'b', 'cd']
sub:作用类似字符串内置函数replace,具体用法是这样re.sub('\d', 'H', 'eva3egon4yuan4', 1)将字符串中的数字替换为H,只替换一次,结果为evaHegon4yuan4
不常用模式
subn:作用和sub差不多,只是会显示替换次数,然后把结果以元祖返回,比如re.subn('\d', 'H', 'eva3egon4yuan4'),结果为('evaHegonHyuanH', 3)
compile:将正则表达式规则进行编译,用法是这样
1 obj = re.compile('\d{3}')View Code
2 ret = obj.search('abc123eeee')
3 print(ret.group())
4 --------------------------------------------------------------------------------------
5 123
finditer:将匹配结果以迭代器的形式返回,用法是这样
1 import reView Code
2 ret = re.finditer('\d', 'ds3sy4784a') #finditer返回一个存放匹配结果的迭代器
3 print(ret) # <callable_iterator object at 0x10195f940>
4 print(next(ret).group()) #查看第一个结果
5 print(next(ret).group()) #查看第二个结果
6 print([i.group() for i in ret]) #查看剩余的左右结果
另外还有一个findall的优先级查询问题,findall默认优先匹配分组中的匹配条件并且只显示分组匹配条件的匹配结果。如果匹配条件中还有其他匹配条件也想显示就在分组中加上?:,比如
1 ret = re.findall('www.(?:baidu|oldboy).com', 'www.oldboy.com')View Code
2 print(ret)
3 --------------------------------------------------------------------------------------
4 ['www.oldboy.com']