Python正则表达式re模块的使用方法

来源:互联网 发布:手写笔绘图软件 编辑:程序博客网 时间:2024/06/05 21:07

1. re的简介

re模块是python中用于文本匹配的模块,尽管不能满足所有复杂的匹配情况,但足够应付大多数的复杂字符串的分析和信息提取。

正则表达式进行文本匹配的一般流程如下所示:


正则表达式字符串(Regular Expression Pattern)经过引擎编译后,生成表达式对象(Regular Expression Object),该对象含有进行匹配所需的信息。需要做匹配的文本,逐个字符逐个字符匹配表达式对象。如果匹配成功,返回的结果将包含匹配到的字符串、分组和在文本中的索引等信息。



2. re的正则表达式语法




3. re的主要功能函数及属性

在介绍具体的模块属性和方法前,先了解一下必要的基本知识。


3.1 原生字符串

import repattern = re.compile(r'name')str = 'my name is moses'mo = re.search(pattern, str)
上面r'name中的‘r’指的是raw(原始)的意思,一般称呼这样的字符串为原生字符串。那么原始字符串有什么用处呢?看下面的例子。

import res = 'Hello\, world'#pattern = re.compile(r'\\')pattern = re.compile('\\\\')mo = re.search(pattern, s)print(mo.group())

正则表达式中“\”是转义字符,这就出现了反斜杠困扰。比如说你要匹配文本中的字符“\”,那么在正则表达式中就需要4个反斜杠"\\\\"。

为什么要4个斜杠呢?是这样子的,第一步,Python会将字符串“\\\\”转义为“\\”,这相当于传入re模块的是"\\",然后第二步,按照正则表达式的转义规则"\\"转义为"\"。

整个过程是很麻烦的。而原始字符串的作用呢,就是让字符串不要考虑转义符,也就相当于不做第一步动作,直接做第二步。因此原始字符串只需要写成r"\\"即可。


3.2 贪婪模式和非贪婪模式

正则匹配默认情况下,会尽可能长的匹配出满足正则表达式对象的结果。

import restr = 'abbbbc'pattern = re.compile(r'ab+')mo = re.search(pattern, str)print(mo.group())
这里给出的正则表达式为"ab+",按理来说可以得到ab,abb,abbb,abbbb四个结果。但是运行结果是abbbb,此时满足条件的字符串最长。这就很贪心了,我们把这种匹配模式称为贪婪模式

有时候我们只想取满足条件的最短字符串,这个时候就要用到非贪婪模式。将上面的"ab+”改为"ab+?",得到的结果为ab,也就是最短的字符串结果。

3.3 匹配模式

上面讲到pattern编译为object的过程,使用了如下方法

re.compile(pattern[, flags])

其中的flags参数,即为正则表达式的匹配模式,具体如下:

re.I  / re.IGNORECASE : 忽略大小写

re.S / re.DOTALL : 点任意匹配模式。使得'.'可用匹配所有字符,包括换行符

re.L / re.LOCALE : 让\w、\W、\b、\B、\s和\S依赖当前的locale

re.M / re.MULTILINE : 多行模式。指定后,'^'会增加匹配每行的开始(也就是换行符后的位置);'$'会增加匹配每行的结束(也就是换行符前的位置)

re.U / re.UNICODE : 让\w、\W、\b、\B、\d、\D、\s和\S依赖Unicode库

re.X / re.VERBOSE : 详细模式。这个模式下正则表达式可以是多行,忽略空白字符,并可以加入注释

如果想设置多个匹配模式,可写成re.compile(pattern, re.I | re.M)的形式。


3.4 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))。 

expand(template): 将匹配到的分组代入template中然后返回。template中可以使用\id或\g<id>、\g<name>引用分组,但不能使用编号0。\id与\g<id>是等价的;但\10将被认为是第10个分组,如果你想表达\1之后是字符'0',只能使用\g<1>0。


3.5 re模块方法

  • search

search(string[,pos[,endpos]])  /  re.search(pattern, string[,flags])

返回MatchObject或None

这个方法用于查找字符串中可以匹配成功的子串。从string的pos下标处起尝试匹配pattern,如果pattern结束时仍可匹配,则返回一个Match对象;若无法匹配,则将pos加1后重新尝试匹配;直到pos=endpos时仍无法匹配则返回None。 

pos和endpos的默认值分别为0和len(string));re.search()无法指定这两个参数,参数flags用于编译pattern时指定匹配模式。  

import repattern = re.compile(r'world')mo = pattern.search('hello world!')#mo = re.search(pattern, 'hello world!')if mo:print(mo.group())
注意这里pattern.search('hello world!')和re.search(pattern, 'hello world!')两种写法没有区别,根据爱好选择。后面的方法都有这两种写法,不再赘述。


  • findall

findall(string[, pos[, endpos]])  /  re.findall(pattern, string[, flags]):

返回所有匹配的List

以列表形式返回全部能匹配的字串。

import re p = re.compile(r'\d+') print p.findall('one1two2three3four4') ### output ### # ['1', '2', '3', '4'] 

  • match

match(string[, pos[, endpos]])  /  re.match(pattern, string[, flags])

返回MatchObject或None

返回结果是Match对象。pos是开始搜索的位置,默认为0。endpos是搜索的结束位置,如果endpos比pos还小的话,结果肯定是空的。也就是说只有pos 到 endpos-1 位置的字符串将会被搜索。

import repattern = re.compile(r'world')mo = pattern.match('hello world!', 6)if mo:print(mo.group())### output ##### world


  • split

split(string[, maxsplit])  /  re.split(pattern, string[, maxsplit])

返回由匹配分割的List

按照能够匹配的子串将string分割后返回列表。maxsplit用于指定最大分割次数,不指定将全部分割。 

pattern = re.compile(r'\d')mo = pattern.split('one1two2three3four4')if mo:print(mo)### output ####['one','two','three','four','']


  • sub

sub(repl, string[, count])  /  re.sub(pattern, repl, string[, count])

返回替换后的字符串

使用repl替换string中每一个匹配的子串后返回替换后的字符串。 

当repl是一个字符串时,可以使用\id或\g<id>、\g<name>引用分组,但不能使用编号0。 

当repl是一个方法时,这个方法应当只接受一个参数(Match对象),并返回一个字符串用于替换(返回的字符串中不能再引用分组)。 

count用于指定最多替换次数,不指定时全部替换。 

import repattern = re.compile(r'(\w+) (\w+)')s = 'i say, hello world!'mo = re.sub(pattern, r'\2 \1', s)  # 这里使用了分组编号print(mo)### output #### say i, world hello!

  • subn

 subn(repl, string[, count])  /  re.sub(pattern, repl, string[, count])

返回 (替换后的字符串, 替换次数)

import repattern = re.compile(r'(\w+) (\w+)')s = 'i say, hello world!'mo = pattern.subn( r'\2 \1', s)  # 这里使用了分组编号print(mo)### output #### ('say i, world hello!', 2)

  • finditer

 finditer(string[, pos[, endpos]])  /  re.finditer(pattern, string[, flags])

返回MatchObject的迭代器

搜索string,返回一个顺序访问每一个匹配结果(Match对象)的迭代器

import re p = re.compile(r'\d+') for m in p.finditer('one1two2three3four4'): print m.group(), ### output ### # 1 2 3 4 


4. 实际使用案例


4.1 提取网页源代码中的超链接

<div><a href="https://support.google.com/chrome/?p=ui_hotword_search" rel="external nofollow" target="_blank">更多</a><p>dfsl</p></div>

使用分组进行文本提取,具体如下:

import res = '<div><a href="https://support.google.com/chrome/?p=ui_hotword_search" rel="external nofollow" target="_blank">更多</a><p>dfsl</p></div>'pattern = re.compile(r'<a.*href="(.*?)".*>')mo = pattern.search(s)print(mo.group(1))

这里用到了分组编号。但是如果对有很多分组的情况,用编号并不是最好选择。此时可以考虑用命名分组,见第2部分的语法表格,命名分组形如

(?P<name>正则表达式)

具体如下

import res = "ip='230.192.168.78',version='1.0.0'"pattern = re.compile(r"ip='(?P<ip>\d+.\d+.\d+.\d+).*")mo = pattern.search(s)print(mo.group('ip'))


4.2 匹配中文字符

import res = "#who#helloworld#a中文x#"pattern = re.compile(r"[\u4e00-\u9fa5]+")mo = pattern.search(s)print(mo.group())### output #### 中文



原创粉丝点击