正则表达式——python(学习记录)
1. 正则表达式基础、简单介绍:正则表达式是搜索替换和解析复杂字符模式的一种强大而标准的方法,正则表达式并不是Python的一部分,他拥有自己的独特语法和独立的处理引擎,效率上可能不如str自带方法,但是功能十分强大。
在提供正则表达式的语言里,正则表达式的语法都是一样的,区别在于不同的编程语言实现的支持语法数量不同,不用担心,不被支持的语法通常都是不常使用的部分。
入门:
作为一个computer student 使用过Windows/Dos下用于文件查找的通配符(wildcard) 即 * 和 ?,那是必须的。如果你想查找某个目录下的所有的Word文档的话,你会搜索 *.doc 。在这里, * 会被解释成任意的字符串。和通配符类似,正则表达式也是用来进行文本匹配的工具,只不过比起通配符,它能更精确地描述你的需求——当然,代价就是更复杂——比如你可以编写一个正则表达式,用来查找 所有以0开头,后面跟着2-、3个数字,然后是一个连字号“--”,最后是7或8位数字的字符串 (像 010--12345678 或 0376--7654321 )。当然你可以这样写:0d{2,3}-d{7,8} , 呵呵没有基础的你是不是觉得这个式子很恶心,其实这基本上算是最简单的正则表达式了,接下来,就请你耐心的看完这篇文章啦!!!!
学习正则表达式的最好方法是从例子开始,理解例子之后再自己对例子进行修改,实验。下面给出了不少简单的例子,并对它们作了详细的说明。且看且珍惜··················
下图展示了使用正则表达式进行匹配的流程:
(该链接为此图出处:http://www.cnblogs.com/huxi/archive/2010/07/04/1771073.html)
正则表达式的大致匹配过程是:依次拿出表达式和文本中的字符比较,如果每一个字符都能匹配,则匹配成功;一旦有匹配不成功的字符则匹配失败。如果表达式中有量词或边界,这个过程会稍微有一些不同,但也是很好理解的。 下图列出了Python支持的正则表达式元字符和语法:
针对上面的图我会给出具体的的实例帮助大家理解。。。。
(出处:正则表达式30分钟入门教程
http://download.csdn.net/detail/wangyezi19930928/7412027
)
表一:常用的元字符:
学习正则表达式的最好方法是从例子开始,理解例子之后再自己对例子进行修改,实验。下面给
出了不少简单的例子,并对它们作了详细的说明。 1)、假设你在一篇英文小说里查找 hi ,你可以使用正则表达式 hi 。这几乎是最简单的正则表达式了,它可以精确匹配这样的字符串: 由两个字符组成,前一个字符是h,后一个是i 。但是很多单词里包含 hi 这两个连续的字符,比如 him,history等。用 hi 来查找的话,这里边的 hi 也会被找出来。如果要 精确地查找hi这个单词 的话,我们应该使用 bhi b 。 b 是正则表达式规定的一个特殊代码(好吧,某些人叫它 元字符,metacharacter ),代表着单词的开头或结尾,也就是单词的分界处 。虽然通常英文的单词是由空格,标点符号或者换行来分隔的,但是 b 并不匹配这些单词分隔字符中的任何一个,它只匹配一个位置。假如你要找的是 hi后面不远处跟着一个Lucy ,你应该用
bhi b.* bLucy b 。这里, . 是另一个元字符,匹配 除了换行符以外的任意字符 。 * 同样是元字符,不过它代表的不是字符,也不是位置,而是数量——它指定* 前边的内容可以连续重复使用任意次以使整个表达式得到匹配。因
此, .* 连在一起就意味着任意数量的不包含换行的字符 。 现在 bhi b.* bLucy b 的意思就很明显了: 先 是一个单词hi,然后是任意个任意字符(但不能是换行),最后是Lucy这个单词 。
2)、比如一个网站如果要求你填写的注册号必须为5位到12位数字时,可以使用: ^ d{5,12}$ 。元字符 ^ (和数字6在同一个键位上的符号)和 $ 都匹配一个位置,这和 b 有点类似。 ^ 匹配你要用来查找的字符串的开头, $ 匹配结尾。这两个代码在验证输入的内容时非常有用。
3)、0dd--d
ddddddd 匹配这样的字符串: 以0开
头,然后是两个数字,然后是一个连字号“-”,最后是8个数
这里的 d 匹配 一位数字(0,或1,或……)。 "-"- 是连字符只匹配它本身,
为了避免那么多烦人的重复,我们也可以这样写这个表达式: 0d{2}--d{8} 。这里 d 后面的 {2}
( {8} )的意思是前面 d 必须连续重复匹配2次(8次) 。
1)、 baw* b 匹配 以字母 a 开头的单词——先是某个单
词开始处( b ),然后是字母 a,然后是任意数量的字母或
数字( w* ),最后是单词结束处( b ) 。
2) d+ 匹配 1个或更多连续的数字 。这里的 + 是和 * 类似的元字符,不同的是 * 匹配 重复任意次(可能 是0次) ,而 + 则匹配 重复1次或更多次 。 3)、 bw{6} b 匹配 刚好6个字符的单词
有时需要查找不属于某个能简单定义的字符类的字符。比如想查找除了数字以外,其它任意字符都行的情况,这时需要用到 反义 。
1)、 S+ 匹配 不包含空白符的字符串 。
2)、<a[^>]+> 匹配用尖括号括起来的以a开头的字符串 。
字符转义():
如果想查找元字符本身的话,比如你查找 .,或者 *,就出现了问题:你没办法指定它们,因为它们会被解释成别的意思。这时你就得使用 来取消这些字符的特殊意义。因此,你应该使用 . 和 * 。当然,查找 本身,得用
1)、taobao.net 匹配 deerchao.net , C: Wi ndows 匹配 C: Wi ndows 。
字符类:
要想查找数字,字母或数字,空白是很简单的,因为已经有了对应这些字符集合的元字符,但是如果你想匹配没有预定义元字符的字符集合(比如元音字母a,e,i,o,u),应该怎么办?很简单,你只需要在方括号里列出它们就行了,像 [aei ou] 就匹配 任何一个英文元音字母 , [.?!] 匹配 标点符号(.或?或!) 。我们也可以轻松地指定一个字符 范围 ,像 [0--9] 代表的含意与 d 就是完全一致的: 一位数字 ;同理 [a--z0--9A--Z_] 也完全等同于 w (如果只考虑英文的话)。
下面是一个更复杂的表达式: (?0 d{2}[)--]? d{8} 。这个表达式可以匹配 几种格式的电话号码 ,像(010)88886666 ,或 022--22334455 ,或 02912345678 等。
分析:首先是一个转义字符 (,它能出现0次或1次( ? ),然后是一个 0 ,后面跟着2个数字( d{2} ),然后是 ) 或 -- 或 空格中的一个,它出现1次或不出现( ? ),最后是8个数字( d{8} )。
分枝条件:
不幸的是,上面的那个表达式也能匹配 010)12345678 或 (022-87654321 这样的“不正确”的格式。要解决这个问题,我们需要用到 分枝条件 。正则表达式里的 分枝条件 指的是有几种规则,如果满足其中任意一种规则都应该当成匹配,具体方法是用 | 把不同的规则分隔开。
例子:
1)、0 d{2}-- d{8}|0 d{3}-- d{7} 这个表达式能 匹配两种以连字号分隔的数字。 2)、 (?0 d{2} )?[--]? d{8}|0 d{2}[--]? d{8} 这个表达式 匹配3位区号的电话号码,其中区号可以用小括号括起来,也可以不用,区号与本地号间可以用连字号或空格间隔,也可以没有间隔 。 3)、 d{5}-- d{4}| d{5} 这个表达式用于匹配美国的邮政编码。美国邮编的规则是5位数字,或者用连字号间隔的9位数字。之所以要给出这个例子是因为它能说明一个问题:使用分枝条件时,要注意各个条件的顺序。如果你把它改成 d{5}| d{5}-- d{4} 的话,那么就只会匹配5位的邮编(以及9位邮编的前5位)。原因是匹配分枝条件时,将会从左到右地测试每个条件,如果满足了某个分枝的话,就不会去再管其它的条件了。
分组:
我们已经提到了怎么重复单个字符(直接在字符后面加上限定符就行了);但如果想要重复多个字符又该怎么办?你可以用小括号来指定 子表达式 (也叫做 分组 ),然后你就可以指定这个子表达式的重复次数了,你也可以对子表达式进行其它一些操作(后面会有介绍)。
( d{1,3} .){3} d{1,3} 是一个 简单的IP地址匹配 表达式。 d{1,3} 匹配 1到3位的数字 , ( d{1,3} .){3} 匹配 三位数字加上一个英文句号(这个整体也就是这个分组)重复3次 ,最后再加上 一个一到三位的数字 ( d{1,3} )。 不幸的是,它也将匹配 256.300.888.999 这种不可能 存在的IP地址。如果能使用算术比较的话,或许能简单 地解决这个问题,但是正则表达式中并不提供关于数学 的任何功能,所以只能使用冗长的分组,选择,字符类 来描述一个正确的IP地址: ((2[0-4] d|25[0-5]|[01]? d d?) .){3}(2[0-4] d|25[0-5]|[01]? d d?) 。
分组使用的实例实在是太多了,这里我们说一部分就可以了:
使用小括号指定一个子表达式后,匹配这个子表达式的文本(也就是此分组捕获的内容)可以在表达式或其它程序中作进一步的处理。默认情况下,每个分组会自动拥有一个 组号 ,规则是:从左向右,以分组的左括号为标志,第一个出现的分组的组号为1,第二个为2,以此类推。
后向引用 用于重复搜索前面某个分组匹配的文本。
例:
1 代表 分组1匹配的文本 。难以理解?请看示例:
b(w+) b s+ 1 b 可以用来匹配 重复的单词 ,像 go go,或
者 ki t t y ki t t y 。这个表达式首先是 一个单词 ,也就是 单词开始
处和结束处之间的多于一个的字母或数字 ( b(w+) b ),这个
单词会被捕获到编号为1的分组中,然后是 1个或几个空白符
( s+ ),最后是 分组1中捕获的内容(也就是前面匹配的那个
单词) ( 1 )。
你也可以自己指定子表达式的 组名 。要指定一个子表达
式的组名,请使用这样的语法: (?<Word>w+) (或者把尖括号
换成 ' 也行: (?'Word'w+) ),这样就把 w+ 的组名指定
为 Word 了。要反向引用这个分组 捕获 的内容,你可以使用 k<Word>,所以上一个例子也可以写成这
样: b(?<Word>w+) b s+ k<Word> b 。
零宽断言:
(?=exp) 也叫零宽度正预测先行断言 ,它断言自身出现的位置的后面能匹配表达式exp 。
比如 bw+(?=i ng b) ,匹配 以i ng结尾的单词的前面部分(除了i ng以外
的部分) ,如查找 I' m si ngi ng whi l e you' re danci ng. 时,它会匹配 si ng 和 danc 。 (?<=exp) 也叫 零宽度正回顾后发断言 ,它 断言自身出现的位置的前面能匹配表达式exp 。
比如 (?
<= bre)w+ b 会匹配 以re开头的单词的后半部分(除了re以外的部分) ,例如在查找 readi ng a book 时,它
匹配 adi ng 。
假如你想要给一个很长的数字中每三位间加一个逗号(当然是从右边加起了),你可以这样查找需要 在前面和里面添加逗号的部分: ((?<= d) d{3})+ b ,用它对 1234567890 进行查找时结果是 234567890 。 下面这个例子同时使用了这两种断言: (?<= s) d+(?= s) 匹配 以空白符间隔的数字(再次强调,不包 括这些空白符) 。
负向零宽断言:
前面我们提到过怎么查找不是某个字符或不在某个字符类里的字符的方法(反义)。但是如果我们只是想要确保某个字符没有出现,但并不想去匹配它时怎么办?
例如,如果我们想查找这样的单词--它里面出现了字母q,但是q后面跟的不是字母u,我们可以尝试这样:
bw*q[^u]w* b 匹配 包含后面不是字母u的字母q的单词 。但是如果多做测试(或者你思维足够敏锐,直接就观察出来了),你会发现,如果q出现在单词的结尾的话,像Iraq,Benq,这个表达式就会出错。这是因为 [^u] 总要匹配一个字符,所以如果q是单词的最后一个字符的话,后面的 [^u] 将会匹配q后面的单词分隔符(可能是空格,或者是句号或其它的什么),后面的 w* b 将会匹配下一个单词,于是 bw*q[^u]w* b 就能匹配整个 Iraq f i ght i ng 。 负向零宽断言 能解决这样的问题,因为它只匹配一个位置,并不消费任何字符。现在,我们可以这样来解决这个问题:
bw*q(?!u)w* b 。
零宽度负预测先行断言 (?!exp) , 断言此位置的后面不能匹配表达式exp 。
例如: d{3}(?! d) 匹配 三位数字,而且这三位数字的后面不能是数字 ;
b((?!abc)w)+ b 匹配 不包含连续字符串abc的单词 。同理,我们可以用 (?<!exp),零宽度负回顾后发断言 来 断言此位置的前面不能匹配表达式exp :
(?<![a-z]) d{7} 匹配 前面不是小写字母的七位数字 。一个更复杂的例子: (?<=<(w+)>).*(?=< / 1>) 匹配 不包含属性的简单HTML标签内里的内容 。 (?<=<(w+)>) 指定了这样的 前缀 : 被尖括号括起来的单词 (比如可能是<b>),然后是 .* (任意的字符串),最后是一个 后缀 (?=< / 1>) 。注意后缀里的 / ,它用到了前面提过的字符转义; 1 则是一个反向引用,引用的正是 捕获的第一组 ,前面的 (w+) 匹配的内容,这样如果前缀实际上是<b>的话,后缀就是</ b>了。整个表达式匹配的是<b>和</ b>之间的内容(再次提醒,不包括前缀和后缀本身)。
注释:
小括号的另一种用途是通过语法 (?#comment )来包含注释。
例如: 2[0-4] d(?#200-249)|25[0-5](?#250-255)|[01]? d d?(?#0-199) 。
要包含注释的话,最好是启用“忽略模式里的空白符”选项,这样在编写表达式时能任意的添加空
格,Tab,换行,而实际使用时这些都将被忽略。启用这个选项后,在#后面到这一行结束的所有文本
都将被当成注释忽略掉。
例如:
( ? < = # 断言要匹配的文本的前缀
< ( w + ) > # 查找尖括号括起来的字母或数字( 即H T M L / X M L 标签) ) # 前缀结束 . * # 匹配任意文本 ( ? = # 断言要匹配的文本的后缀 < / 1 > # 查找尖括号括起来的内容:前面是一个" / " ,后面是先前捕获的标签 ) # 后缀结束
贪婪与懒惰:
当正则表达式中包含能接受重复的限定符时,通常的行为是(在使整个表达式能得到匹配的前提下)匹配尽可能多的字符。
例:
a.*b ,它将会匹配 最长的以a开始,以b结束的字符串 。如果用它来搜索 aabab 的话,它会匹配整个字符串 aabab 。这被称为 贪婪 匹配。
有时,我们更需要 懒惰 匹配,也就是匹配尽可能少的字符。前面给出的限定符都可以被转化为懒惰匹配模式,只要在它后面加上一个问号 ?。这样 .*? 就意味着 匹配任意数量的重复,但是在能使整个匹配成功的前提下使用最少的重复 。
例:
a.*?b 匹配 最短的,以a开始,以b结束的字符串 。如果把它应用于 aabab 的话,它会匹配 aab(第一到第三个字符) 和 ab(第四到第五个字符) 。 注: 你可能发问了:既然是懒惰匹配,为什么第一个匹配是aab(第一到第三个字符)而不是ab(第二到第三个字符)?简单地说,因为正则表达式有另一条规则,且比懒惰 / 贪婪规则的优先级更高:最先开始的匹配拥有最高的优先权。
平衡组/递归匹配:
有时我们需要匹配像 ( 100 * ( 50 + 15 ) )这样的可嵌套的层次性结构 ,这时简单地使用 (.+ ) 则只会匹配到
最左边的左括号和最右边的右括号之间的内容(这里我们讨论的是贪婪模式,懒惰模式也有下面的问题)。假 如原来的字符串里的左括号和右括号出现的次数不相等,比如 ( 5 / ( 3 + 2 ) ) ) ,那我们的匹配结果里两者的个数也不会相等。有没有办法在这样的字符串里匹配到最长的,配对的括号之间的内容呢? 为了避免 ( 和 ( 把你的大脑彻底搞糊涂,我们还是用尖括号代替圆括号吧。现在我们的问题变成了如何把
xx <aa <bbb> <bbb> aa> yy 这样的字符串里,最长的配对的尖括号内的内容捕获出来?
这里需要用到以下的语法构造: (?'group') 把捕获的内容命名为group,并压入 堆栈(Stack) (?'--group') 从堆栈上弹出最后压入堆栈的名为group的捕获内容,如果堆栈本来为空,则本分组的匹配失败 (?(group)yes|no) 如果堆栈上存在以名为group的捕获内容的话,继续匹配yes部分的表达式,否则继续匹配no部分 (?!) 零宽负向先行断言,由于没有后缀表达式,试图匹配总是失败 我们需要做的是每碰到了左括号,就在压入一个"Open",每碰到一个右括号,就弹出一个,到了最后就看看堆栈是否为空--如果不为空那就证明左括号比右括号多,那匹配就应该失败。正则表达式引擎会进行回溯(放弃最前面或最后面的一些字符),尽量使整个表达式得到匹配。 < # 最外层的左括号 [ ^ < > ] * # 最外层的左括号后面的不是括号的内容 ( ( ( ? ' O p e n ' < ) # 碰到了左括号,在黑板上写一个" O p e n " [ ^ < > ] * # 匹配左括号后面的不是括号的内容 ) + ( ( ? ' - O p e n ' > ) # 碰到了右括号,擦掉一个" O p e n " [ ^ < > ] * # 匹配右括号后面不是括号的内容 ) + ) * ( ? ( O p e n ) ( ? ! ) ) # 在遇到最外层的右括号前面,判断黑板上还有没有没擦掉的" O p e n " ;如果 还有,则匹配失败 > # 最外层的右括号 平衡组的一个最常见的应用就是匹配HTML,下面这个例子可以匹配 嵌套的<di v>标签 :
<di v[^>]*>
[^<>]*(((?'Open'<di v[^>]*>)[^<>]*)+((?'-Open'</ di v>)[^<>]*)+)*(?(Open)(?!))</ di v> .
。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
到这里正则表达式的基本内容就说的差不多了
接下来我们就进入正题就是如何在Python中使用正则表达式
如果你要解决的问题利用字符串函数能够完成,你应该使用它们。它们快速、
简单且容易阅读,而快速、简单、可读性强的代码可以说出很多好处。但是, 如果你发现你使用了许多不同的字符串函数和 if 语句来处理一个特殊情况, 或者你组合使用了 split、join 等函数而导致用一种奇怪的甚至读不下去的方式 理解列表,此时,你也许需要转到正则表达式了。
(出处:深入学习Python第七章http://download.csdn.net/detail/wangyezi19930928/7412551)
。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
正如前面所说:正则表达式并不是Python的一部分,但是Python语言里提供了正则表达式:
1)、
<span style="font-size:18px;">>>> S = "100 north main road" >>> S.replace('road','rd') #使用字符串方法 '100 north main rd' >>> S = "100 north broad road" #这里使用字符串方法出现问题,我们的目的是替换road,但是broad 中的子字符串也被替换掉 >>> S.replace('road','rd') '100 north brd rd' >>> S[:-4]+S[-4:].replace('road','rd.') #使用字符串中的索引和分片方法解决,但是代码可读性差 '100 north broad rd.' >>> import re #使用正则表达式,re为Python为支持正则表达式提供的模块 >>> re.sub('road$','rd',S) #这个正则表达式十分简单,road$:只有road出现在一个字符串尾部时才匹配,$表示“字符串的末尾”,利用re.sub对字符串进行搜索,满足正则表达式road$的用rd替换 '100 north broad rd'</span> <span style="font-size:18px;"></span><span style="font-family: monospace; white-space: pre; "><span style="font-size:18px;">>>> S = '100BROAD'</span></span> <span style="font-size:18px;"><span style="font-family: monospace; white-space: pre; "></span>>>> re.sub('ROAD$','RD',S) #只有当ROAD出现在字符串末尾时替换 '100BRD' >>> re.sub('bROAD$',S)#只有当ROAD出现在字符串尾部并且作为一个独立的单词时替换,b表示单词的边界,第一个为转移字符</span> <span style="font-size:18px;"> >>> re.sub(r'bROAD$',S) #这是上面的改良版,使用了Python的Raw字符 '100BROAD'</span></span> <span style="font-size:18px;">>>> S = '100BROAD200' >>> re.sub(r'bROADb',S) #当ROAD不在末尾时,上面的匹配就会失败,所以在这里给ROAD的前后都加上b(单词边界),这样就能匹配整个字符串中的所有的ROAD了。神奇有木有 '100BROAD200' >>> S = '100 BROAD 200' >>> re.sub(r'bROADb',S) '100 BROAD 200' >>> S = '100 BROAD ROAD 200' >>> re.sub(r'bROADb',S) '100 BROAD RD 200'</span> 一些Python 的RE方法及其应用(https://docs.python.org/2/library/re.html)<span style="font-size:18px;">>>> import re >>> help (re) This module exports the following functions:</span> <span style="font-size:18px;"> match Match a regular expression pattern to the beginning of a string. search Search a string for the presence of a pattern. sub Substitute occurrences of a pattern found in a string. subn Same as sub,but also return the number of substitutions made. split Split a string by the occurrences of a pattern. findall Find all occurrences of a pattern in a string. finditer Return an iterator yielding a match object for each match. compile Compile a pattern into a RegexObject. purge Clear the regular expression cache. escape Backslash all non-alphanumerics in a string. Some of the functions in this module takes flags as optional parameters: I IGNORECASE Perform case-insensitive matching. L LOCALE Make w,W,b,B,dependent on the current locale. M MULTILINE "^" matches the beginning of lines (after a newline) as well as the string. "$" matches the end of lines (before a newline) as well as the end of the string. S DOTALL "." matches any character at all,including the newline. X VERBOSE Ignore whitespace and comments for nicer looking RE's. U UNICODE Make w,dependent on the Unicode locale. </span> <span style="font-size:18px;">>>> help (re.match) 这样查看每个方法的帮助文档,可以看到每一种方法的参数 match(pattern,string,flags=0) Try to apply the pattern at the start of the string,returning a match object,or None if no match was found. (END)</span>
下面就让我们用例子来一一说明上述方法:
1)、Python通过 re 模块提供对正则表达式的支持。使用 re 的一般步骤是先将正则表达式的字符串形式编译为Pattern实例,然后使用Pattern实例处理文本并获得匹配结果(一个Match实例),最后使用Match实例获得信息,进行其他的操作。
<span style="font-size:18px;">>>> pattern = re.compile(r'hello') # 将正则表达式编译成Pattern对象 >>> match = pattern.match('hello world!') #使用Pattern匹配文本,获得匹配结果,无法匹配时将返回None >>> if match: ... print match.group() #获得一个或多个分组截获的字符串;</span></span><span style="font-size:18px;"> ... hello</span> re.compile(strPattern[,flag]): 这个方法是Pattern类的工厂方法,用于将字符串形式的正则表达式编译为Pattern对象。 第二个参数flag是匹配模式,取值可以使用按位或运算符'|'表示同时生效,比如re.I | re.M。另外,你也可以在regex字符串中指定模式,比如re.compile('pattern',re.I | re.M)与re.compile('(?im)pattern')是等价的。
re提供了众多模块方法用于完成正则表达式的功能。这些方法可以使用Pattern实例的相应方法替代,唯一的好处是少写一行re.compile()代码,但同时也无法复用编译后的Pattern对象。这些方法将在Pattern类的实例方法部分一起介绍。如上面这个例子可以简写为:
<span style="font-size:18px;">>>> m = re.match(r'hello','hello world') >>> print m.group() hello </span> 2)、Match
<span style="font-size:18px;">>>> help(re.match) Help on function match in module re: match(pattern,flags=0) Try to apply the pattern at the start of the string,returning a match object,or None if no match was found.</span> match()函数只检测pattern是不是在string的开始位置匹配, 也就是说match()只有在0位置匹配成功的话才有返回,如果不是开始位置匹配成功的话,match()就返回none。 eg:
<span style="font-size:18px;">>>> print re.match(r'hello','hello world').group() hello >>> print re.match(r'hello','Python hello world').group() Traceback (most recent call last): File "<stdin>",line 1,in <module> AttributeError: 'NoneType' object has no attribute 'group'</span> Match对象是一次匹配的结果,包含了很多关于此次匹配的信息,可以使用Match提供的可读属性或方法来获取这些信息。 属性:
方法:
<span style="font-size:18px;">>>> m = re.match(r'python','python hello') >>> print m.group() #获取分组截获的字符串 python >>> print m.string #获取匹配时使用的文本 python hello >>> print m.re #匹配时使用的Pattern对象(先将正则表达式的字符串形式编译为Pattern实例, 然后使用Pattern实例处理文本并获得匹配结果) <_sre.SRE_Pattern object at 0xb7458bd0> >>> print m.pos #文本中正则表达式开始搜索的索引</span> 0 >>> print m.endpos #文本中正则表达式结束搜索的索引,与len(string)相同</span> 12 >>> print m.lastindex #最后一个被捕获的分组在文本中的索引。如果没有被捕获的分组,将为None</span> None >>> print m.lastgroup #最后一个被捕获的分组的别名。如果这个分组没有别名或者没有被捕获的分组,将 为None None >>> print m.groups() 以元组形式返回全部分组截获的字符串</span> () >>> print m.groupdict() {} >>> print m.start() 0 >>> print m.end() 6 >>> print m.span() (0,6)</span> 3)、 Pattern Pattern对象是一个编译好的正则表达式,通过Pattern提供的一系列方法可以对文本进行匹配查找。 Pattern不能直接实例化,必须使用re.compile()进行构造。 Pattern提供了几个可读属性用于获取表达式的相关信息:
s
earch(pattern,flags=0):
re.search()会扫描整个字符串并返回第一个成功的匹配,如果匹配不上返回 None。
match VS search:re.match 从字符串的开始处开始匹配,如果字符串开始不符合正则表达式,则匹配失败,函数返回None;而re.search 查找整个字符串,直到找到一个匹配;若无匹配返回None。<span style="font-size:18px;">>>> print re.match(r'hello','python hello world').group() Traceback (most recent call last): File "<stdin>",in <module> AttributeError: 'NoneType' object has no attribute 'group' >>> print re.search(r'hello','python hello world').group() hello </span>
4)、 sub
sub(pattern,repl,count=0):
使用
repl替换string中每一个匹配的子串后返回替换后的字符串。
当repl是一个字符串时,可以使用id或g<id>、g<name>引用分组,但不能使用编号0。
当repl是一个方法时,这个方法应当只接受一个参数(Match对象),并返回一个字符串用于替换(返回的字符串中不能再引用分组)。
count用于指定最多替换次数,不指定时全部替换。
<span style="font-size:18px;">>>> p = re.compile(r'(w+) (w+)') #‘(w+) (w+)’空格连接的两个单词 >>> s = 'i say,hello world!' >>> print p.sub(r'2 1',s) #以id引用分组,将每个匹配中的两个单词掉转位置 say i,world hello! >>> def func(m): #将匹配单词的首字母改为大写 ... return m.group(1).title() + ' ' + m.group(2).title() ... >>> print p.sub(func,s) I Say,Hello World!</span> subn subn(pattern,count=0,flags=0):此函数的参数与 sub 函数完全一致,只不过其返回值是包括两个元素的元组:(new_string,number);第一个返回值new_string 为sub 函数的结果,第二个 number 为匹配及替换的次数。 <span style="font-size:18px;">>>> import re >>> p = re.compile(r'(w+) (w+)') >>> s = 'i say,hello world!' >>> print p.subn(r'2 1',s) ('say i,world hello!',2) >>> def func(m): ... return m.group(1).title() + ' ' + m.group(2).title() ... >>> print p.subn(func,s) ('I Say,Hello World!',2)</span> 4)、findall
findall(pattern,flags=0):搜索string,以列表形式返回全部能匹配的子串。返回值格式为一个列表
<span style="font-size:18px;">>>> p = re.compile(r'bwb') >>> print p.findall('one 1 two 2 three 3 four 4') ['1','2','3','4'] >>> p = re.compile(r'bw+b') >>> print p.findall('one 1 two 2 three 3 four 4') ['one','1','two','three','four','4']</span> 5)、finditer |