初学PythonQ对Python的文字处理能力有很深的印象,除了str对象自带的一些方法外Q就是正则表辑ּq个强大的模块了。但是对于初学者来_要用好这个功能还是有炚w?br />
Q我׃好长旉才摸Z炚w道。由于我记性不好,很容易就忘事Q所以还是写下来比较好一些,同时也可以加深印象,整理思\?br />
׃我是初学Q所以肯定会有些错误Q还望高手不吝赐教,指出我的错误?br />
1 Python正则式的基本用法
Python的正则表辑ּ的模块是‘re’,它的基本语法规则是指定一个字W序列,比如你要在一个字W串s=’123abc456’中查扑֭W串’abc’,只要q样写:
>>> import re
>>> s='123abc456eabc789'
>>> re.findall(r’abc’,s)
l果是Q?br />
['abc', 'abc']
q里用到的函?#8221;findall(rule , target [,flag] )” 是个比较直观的函敎ͼ是在目标字W串中查扄合规则的字符丌Ӏ第一个参数是规则Q第二个参数是目标字W串Q后?br />
q可以跟一个规则选项Q选项功能在compile函数的说明中详细说明Q。返回结果结果是一个列表,中间存放的是W合规则的字W串。如果没有符合规则的字符串被扑ֈQ就q?br />
回一个空列表?br />
Z么要用r’ ..‘字符Ԍraw字符ԌQ由于正则式的规则也是由一个字W串定义的,而在正则式中大量使用转义字符’/’Q如果不用raw字符Ԍ则在需要写一?#8217;/’的地
方,你必d写成’//’,那么在要从目标字W串中匹配一?#8217;/’的时候,你就得写??#8217;/’成ؓ’////’Q这当然很麻烦,也不直观Q所以一般都使用r’’来定义规则字W?br />
丌Ӏ当Ӟ某些情况下,可能不用raw字符串比较好?br />
以上是个最单的例子。当然实际中q么单的用法几乎没有意义。ؓ了实现复杂的规则查找Qre规定了若q语法规则。它们分么几c:
功能字符Q?nbsp; ‘.’ ‘*’ ‘+’ ‘|’ ‘?’ ‘^’ ‘$’ ‘/’{,它们有特D的功能含义。特别是’/’字符Q它是{义引导符P跟在它后面的字符一般有Ҏ的含义?br />
规则分界W: ‘[‘ ‘]’ ‘Q?#8217; ‘Q?#8217; ‘{‘ ‘}’{,也就是几U括号了?br />
预定义{义字W集Q?#8220;/d” “/w” “/s” {等Q它们是以字W?#8217;/’开_后面接一个特定字W的形式Q用来指CZ个预定义好的含义?br />
其它Ҏ功能字符Q?#8217;#’ ‘!’ ‘:’ ‘-‘{,它们只在特定的情况下表示Ҏ的含义,比如(?# …)pCZ个注释,里面的内容会被忽略?br />
下面来一个一个的说明q些规则的含义,不过说明的顺序ƈ不是按照上面的顺序来的,而是我认为由入深,由基本到复杂的顺序来~排的。同时ؓ了直观,在说明的q程中尽?br />
多D些例子以方便理解?br />
1.1基本规则
‘[‘ ‘]’字符集合讑֮W?br />
首先说明一下字W集合设定的Ҏ。由一Ҏ括号括v来的字符Q表明一个字W集合,能够匚w包含在其中的L一个字W。比如[abc123]Q表明字W?#8217;a’ ‘b’ ‘c’ ‘1’
‘2’ ‘3’都符合它的要求。可以被匚w?br />
?#8217;[‘ ‘]’中还可以通过’-‘ 减号来指定一个字W集合的范围Q比如可以用[a-zA-Z]来指定所以英文字母的大小写,因ؓ英文字母是按照从到大的序来排的。你不可?br />
把大的序颠倒了Q比如写成[z-a]׃对了?br />
如果?#8217;[‘ ‘]’里面的开头写一?#8216;^’ P则表C取非,卛_括号里的字符都不匚w。如[^a-zA-Z]表明不匹配所有英文字母。但是如?#8216;^’不在开_则它׃再是表示
取非Q而表C其本nQ如[a-z^A-Z]表明匚w所有的英文字母和字W?#8217;^’?br />
‘|’ 或规?br />
两个规则ƈ列v来,?#8216;|’q接Q表C只要满_中之一可以匹配。比?br />
[a-zA-Z]|[0-9]表示满数字或字母就可以匚wQ这个规则等价于[a-zA-Z0-9]
注意Q关?#8217;|’要注意两点:
W一Q?nbsp; 它在’[‘ ‘]’之中不再表示或,而表CZ本n的字W。如果要?#8217;[‘ ‘]’外面表示一?#8217;|’字符Q必ȝ反斜杠引|?#8217;/|’ ;
W二Q?nbsp; 它的有效范围是它两边的整条规则,比如‘dog|cat’匚w的是‘dog’?#8217;cat’Q而不?#8217;g’?#8217;c’。如果想限定它的有效范围Q必需使用一个无捕获l?#8216;
(?: )’包v来。比如要匚w‘I have a dog’?#8217;I have a cat’Q需要写成r’I have a (?:dog|cat)’Q而不能写成r’I have a dog|cat’
?br />
>>> s = ‘I have a dog , I have a cat’
>>> re.findall( r’I have a (?:dog|cat)’ , s )
['I have a dog', 'I have a cat'] #正如我们所要的
下面再看看不用无捕获l会是什么后果:
>>> re.findall( r’I have a dog|cat’ , s )
['I have a dog', 'cat'] #它将’I have a dog’?#8217;cat’当成两个规则?br />
至于无捕L的用,后面仔l说明。这里先跌?br />
‘.’ 匚w所有字W?br />
匚w除换行符’/n’外的所有字W。如果用了’S’选项Q匹配包?#8217;/n’的所有字W?br />
例:
>>> s=’123 /n456 /n789’
>>> findall(r‘.+’,s)
['123', '456', '789']
>>> re.findall(r‘.+’ , s , re.S)
['123/n456/n789']
‘^’?#8217;$’匚w字符串开头和l尾
注意’^’不能?#8216;[ ]’中,否则含意发生变化,具体L上面?#8217;[‘ ‘]’说明。在多行模式下,它们可以匚w每一行的行首和行。具体请看后面compile函数说明?#8217;M
’选项部分
‘/d’匚w数字
q是一个以’/’开头的转义字符Q?#8217;/d’表示匚w一个数字,即等价于[0-9]
‘/D’匚w非数?br />
q个是上面的反集Q即匚w一个非数字的字W,{h于[^0-9]。注意它们的大小写。下面我们还看到Python的正则规则中很多转义字符的大写形式Q代表互补的关系。这样很
好记?br />
‘/w’匚w字母和数?br />
匚w所有的英文字母和数字,即等价于[a-zA-Z0-9]?br />
‘/W’匚w非英文字母和数字
?#8217;/w’的补集,{h于[^a-zA-Z0-9]?br />
‘/s’匚w间隔W?br />
卛_配空格符、制表符、回车符{表C分隔意义的字符Q它{h于[ /t/r/n/f/v]。(注意最前面有个I格)
‘/S’匚w非间隔符
即间隔符的补集,{h于[^ /t/r/n/f/v]
‘/A’匚w字符串开?br />
匚w字符串的开头。它?#8217;^’的区别是Q?#8217;/A’只匹配整个字W串的开_即?#8217;M’模式下,它也不会匚w其它行的很首?br />
‘/Z’匚w字符串结?br />
匚w字符串的l尾。它?#8217;$’的区别是Q?#8217;/Z’只匹配整个字W串的结,即?#8217;M’模式下,它也不会匚w其它各行的行?br />
例:
>>> s= '12 34/n56 78/n90'
>>> re.findall( r'^/d+' , s , re.M ) #匚w位于行首的数?br />
['12', '56', '90']
>>> re.findall( r’/A/d+’, s , re.M ) #匚w位于字符串开头的数字
['12']
>>> re.findall( r'/d+$' , s , re.M ) #匚w位于行尾的数?br />
['34', '78', '90']
>>> re.findall( r’/d+/Z’ , s , re.M ) #匚w位于字符串尾的数?br />
['90']
‘/b’匚w单词边界
它匹配一个单词的边界Q比如空格等Q不q它是一?#8216;0’长度字符Q它匚w完的字符串不会包括那个分界的字符。而如果用’/s’来匹配的话,则匹配出的字W串中会包含那个
分界W?br />
例:
>>> s = 'abc abcde bc bcd'
>>> re.findall( r’/bbc/b’ , s ) #匚w一个单独的单词‘bc’ Q而当它是其它单词的一部分的时候不匚w
['bc'] Q只扑ֈ了那个单独的’bc’
>>> re.findall( r’/sbc/s’ , s ) Q匹配一个单独的单词‘bc’
[' bc '] #只找到那个单独的’bc’Q不q注意前后有两个I格Q可能有点看不清?br />
‘/B’匚w非边?br />
?#8217;/b’相反Q它只匹配非边界的字W。它同样是个0长度字符?br />
接上例:
>>> re.findall( r’/Bbc/w+’ , s ) #匚w包含’bc’但不?#8217;bc’为开头的单词
['bcde'] #成功匚w?#8217;abcde’中的’bcde’Q而没有匹?#8217;bcd’
‘(?:)’无捕L
当你要将一部分规则作ؓ一个整体对它进行某些操作,比如指定光复次数时Q你需要将q部分规则用’(?:’ ‘)’把它包围hQ而不能仅仅只用一ҎP那样得到绝?br />
Zh意料的结果?br />
例:匚w字符串中重复?#8217;ab’
>>> s=’ababab abbabb aabaab’
>>> re.findall( r’/b(?:ab)+/b’ , s )
['ababab']
如果仅用一ҎP看看会是什么结果:
>>> re.findall( r’/b(ab)+/b’ , s )
['ab']
q是因ؓ如果只用一ҎP那么q就成ؓ了一个组(group)。组的用比较复杂,在后面详细讲解?br />
‘(?# )’注释
Python允许你在正则表达式中写入注释Q在’(?#’ ‘)’之间的内容将被忽略?br />
(?iLmsux) ~译选项指定
Python的正则式可以指定一些选项Q这个选项可以写在findall或compile的参CQ也可以写在正则式里Q成为正则式的一部分。这在某些情况下会便利一些。具体的选项含义?br />
看后面的compile函数的说明?br />
此处~译选项’i’{h于IGNORECASE QL {h?LOCAL Qm {h?MULTILINEQs{h?DOTALL Qu{h于UNICODE Q?x {h?VERBOSE?br />
h意它们的大小写。在使用时可以只指定一部分Q比如只指定忽略大小写,可写?#8216;(?i)’Q要同时忽略大小写ƈ使用多行模式Q可以写?#8216;(?im)’?br />
另外要注意选项的有效范围是整条规则Q即写在规则的Q何地方,选项都会对全部整条正则式有效?br />
1.2重复
正则式需要匹配不定长的字W串Q那׃定需要表C重复的指示W。Python的正则式表示重复的功能很丰富灉|。重复规则的一般的形式是在一条字W规则后面紧跟一个表C重?br />
ơ数的规则,已表明需要重复前面的规则一定的ơ数。重复规则有Q?br />
‘*’ 0或多ơ匹?br />
表示匚w前面的规?ơ或多次?br />
‘+’ 1ơ或多次匚w
表示匚w前面的规则至?ơ,可以多次匚w
例:匚w以下字符串中的前一部分是字母,后一部分是数字或没有的变量名?br />
>>> s = ‘ aaa bbb111 cc22cc 33dd ‘
>>> re.findall( r’/b[a-z]+/d*/b’ , s ) #必须臛_1个字母开_以连l数字结或没有数字
['aaa', 'bbb111']
注意上例中规则前后加了表C单词边界的’/b’指示W,如果不加的话l果׃变成Q?br />
>>> re.findall( r’[a-z]+/d*’ , s )
['aaa', 'bbb111', 'cc22', 'cc', 'dd'] #把单词给拆开?br />
大多数情况下q不是我们期望的l果?br />
‘?’ 0?ơ匹?br />
只匹配前面的规则0ơ或1ơ?br />
例,匚w一个数字,q个数字可以是一个整敎ͼ也可以是一个科学计数法记录的数字,比如123?0e3都是正确的数字?br />
>>> s = ‘ 123 10e3 20e4e4 30ee5 ‘
>>> re.findall( r’ /b/d+[eE]?/d*/b’ , s )
['123', '10e3']
它正匹配了123?0e3,正是我们期望的。注意前后的’/b’的用,否则得C期望的结果?br />
1.2.1 _匚w和最匹?br />
Python正则式还可以_指定匚w的次数。指定的方式?br />
‘{m}’ _匚wm?br />
‘{m,n}’ 匚w最mơ,最多nơ?n>m)
如果你只x定一个最次数或只指定一个最多次敎ͼ你可以把另外一个参数空h。比如你x定最?ơ,可以写成{3,}Q注意那个逗号Q,同样如果只想指定最大ؓ5ơ,?br />
以写成{Q?}Q也可以写成{0,5}?br />
例寻找下面字W串?br />
aQ?位数
b: 2位数?位数
c: 5位数以上的数
d: 4位数以下的数
>>> s= ‘ 1 22 333 4444 55555 666666 ‘
>>> re.findall( r’/b/d{3}/b’ , s ) # aQ?位数
['333']
>>> re.findall( r’/b/d{2,4}/b’ , s ) # b: 2位数?位数
['22', '333', '4444']
>>> re.findall( r’/b/d{5,}/b’, s ) # c: 5位数以上的数
['55555', '666666']
>>> re.findall( r’/b/d{1,4}/b’ , s ) # 4位数以下的数
['1', '22', '333', '4444']
‘*?’ ‘+?’ ‘??’最匹?br />
‘*’ ‘+’ ‘?’通常都是可能多的匹配字W。有时候我们希望它可能少的匹配。比如一个c语言的注?#8216;/* part 1 */ /* part 2 */’Q如果用最大规则:
>>> s =r ‘/* part 1 */ code /* part 2 */’
>>> re.findall( r’//*.*/*/’ , s )
[‘/* part 1 */ code /* part 2 */’]
l果把整个字W串都包括进M。如果把规则改写?br />
>>> re.findall( r’//*.*?/*/’ , s ) #?后面加上?Q表C尽可能的匚w
['/* part 1 */', '/* part 2 */']
l果正确的匹配出了注释里的内?br />
1.3 前向界定与后向界?br />
有时候需要匹配一个跟在特定内容后面的或者在特定内容前面的字W串QPython提供一个简便的前向界定和后向界定功能,或者叫前导指定和跟从指定功能。它们是Q?br />
‘(?<=…)’前向界定
括号?#8217;…’代表你希望匹配的字符串的前面应该出现的字W串?br />
‘(?=…)’ 后向界定
括号中的’…’代表你希望匹配的字符串后面应该出现的字符丌Ӏ?br />
例:你希望找出c语言的注释中的内容,它们是包含在’/*’?#8217;*/’之间Q不q你q不希望匚w的结果把’/*’?#8217;*/’也包括进来,那么你可以这LQ?br />
>>> s=r’/* comment 1 */ code /* comment 2 */’
>>> re.findall( r’(?<=//*).+?(?=/*/)’ , s )
[' comment 1 ', ' comment 2 ']
注意q里我们仍然使用了最匹配,以避免把整个字符串给匚wq去了?br />
要注意的是,前向界定括号中的表达式必L常|也即你不可以在前向界定的括号里写正则式。比如你如果在下面的字符串中x到被字母夹在中间的数字,你不可以用前向界
定:
例:
>>> s = ‘aaa111aaa , bbb222 , 333ccc ‘
>>> re.findall( r’(?<=[a-z]+)/d+(?=[a-z]+)' , s ) #错误的用?br />
它会l出一个错误信息:
error: look-behind requires fixed-width pattern
不过如果你只要找出后面接着有字母的数字Q你可以在后向界定写正则式:
>>> re.findall( r’/d+(?=[a-z]+)’, s )
['111', '333']
如果你一定要匚w包夹在字母中间的数字Q你可以使用l(groupQ的方式
>>> re.findall (r'[a-z]+(/d+)[a-z]+' , s )
['111']
l的使用在后面详细讲解?br />
除了前向界定前向界定和后向界定外Q还有前向非界定和后向非界定Q它的写法ؓQ?br />
‘(?<!...)’前向非界?br />
只有当你希望的字W串前面不是’…’的内Ҏ才匹?br />
‘(?!...)’后向非界?br />
只有当你希望的字W串后面不跟着’…’内容时才匚w?br />
接上例,希望匚w后面不跟着字母的数?br />
>>> re.findall( r’/d+(?!/w+)’ , s )
['222']
注意q里我们使用?w而不是像上面那样用[a-z]Q因为如果这样写的话Q结果会是:
>>> re.findall( r’/d+(?![a-z]+)’ , s )
['11', '222', '33']
q和我们期望的似乎有点不一栗它的原因,是因?#8217;111’?#8217;222’中的前两个数字也是满个要求的。因此可看出Q正则式的用还是要相当心的,因ؓ我开始就是这?br />
写的Q看到结果后才明白过来。不qPython试验h很方便,q也是脚本语a的一大优点,可以一步一步的试验Q快速得到结果,而不用经q烦琐的~译、链接过E。也因此学习
Pythonp多试Q跌跌撞撞的走过来,虽然曲折Q却也很有乐?br />
1.4l的基本知识
上面我们已经看过了Python的正则式的很多基本用法。不q如果仅仅是上面那些规则的话Q还是有很多情况下会非常ȝQ比如上面在讲前向界定和后向界定Ӟ取夹在字母中?br />
的数字的例子。用前面讲过的规则都很难辑ֈ目的Q但是用了组以后很单了?br />
‘(‘’)’ 无命名组
最基本的组是由一对圆括号括v来的正则式。比如上面匹配包夹在字母中间的数字的例子中用的(/d+)Q我们再回顾一下这个例子:
>>> s = ‘aaa111aaa , bbb222 , 333ccc ‘
>>> re.findall (r'[a-z]+(/d+)[a-z]+' , s )
['111']
可以看到findall函数只返回了包含?#8217;()’中的内容Q而虽然前面和后面的内定w匚w成功了,却ƈ不包含在l果中?br />
除了最基本的Ş式外Q我们还可以l组起个名字Q它的Ş式是
‘(?P<name>…)’命名l?br />
‘(?P’代表q是一个Python的语法扩?#8217;<…>’里面是你l这个组L名字Q比如你可以l一个全部由数字l成的组叫做’num’Q它的Ş式就?#8217;(?P<num>/d+)’。v了名字之
后,我们可以在后面的正则式中通过名字调用q个l,它的形式?br />
‘(?P=name)’调用已匹配的命名l?br />
要注意,再次调用的这个组是已被匹配的l,也就是说它里面的内容是和前面命名l里的内Ҏ一L?br />
我们可以看更多的例子Q请注意下面q个字符串各子串的特炏V?br />
>>> s='aaa111aaa,bbb222,333ccc,444ddd444,555eee666,fff777ggg'
我们看看下面的正则式会返回什么样的结果:
>>> re.findall( r'([a-z]+)/d+([a-z]+)' , s ) #扑և中间Ҏ数字的字?br />
[('aaa', 'aaa'), ('fff', 'ggg')]
>>> re.findall( r '(?P<g1>[a-z]+)/d+(?P=g1)' , s ) #扑և被中间夹有数字的前后同样的字?br />
['aaa']
>>> re.findall( r'[a-z]+(/d+)([a-z]+)' , s ) #扑և前面有字母引|中间是数字,后面是字母的字符串中的中间的数字和后面的字母
[('111', 'aaa'), ('777', 'ggg')]
我们可以通过命名l的名字在后面调用已匚w的命名组Q不q名字也不是必需的?br />
‘/number’ 通过序号调用已匹配的l?br />
正则式中的每个组都有一个序P序号是按l从左到叻I?开始的数字Q你可以通过下面的Ş式来调用已匹配的l?br />
比如上面扑և被中间夹有数字的前后同样的字母的例子Q也可以写成Q?br />
>>> re.findall( r’([a-z]+)/d+/1’ , s )
['aaa']
l果是一L?br />
我们再看一个例?br />
>>> s='111aaa222aaa111 , 333bbb444bb33'
>>> re.findall( r'(/d+)([a-z]+)(/d+)(/2)(/1)' , s ) #扑և完全对称的数字-字母Q数字-字母Q数字中的数字和字母
[('111', 'aaa', '222', 'aaa', '111')]
Python2.4以后的re模块Q还加入了一个新的条件匹配功?br />
‘(?(id/name)yes-pattern|no-pattern)’ 判断指定l是否已匚wQ执行相应的规则
q个规则的含义是Q如果id/name指定的组在前面匹配成功了Q则执行yes-pattern的正则式Q否则执行no-pattern的正则式?br />
举个例子Q比如要匚w一些Ş如usr@mail的邮地址Q不q有的写?lt; usr@mail >即用一?lt;>括v来,有点则没有,要匹配这两种情况Q可以这样写
>>> s='<usr1@mail1> usr2@maill2'
>>> re.findall( r'(<)?/s*(/w+@/w+)/s*(?(1)>)' , s )
[('<', 'usr1@mail1'), ('', 'usr2@maill2')]
不过如果目标字符串如?br />
>>> s='<usr1@mail1> usr2@maill2 <usr3@mail3 usr4@mail4> < usr5@mail5 '
而你惛_到要么由一?lt;>包围h的一个邮件地址Q要么得C个没有被<>包围h的地址Q但不想得到一?lt;>中间包围的多个地址或不完整?lt;>中的地址Q那么用这个式子ƈ
不能得到你想要的l果
>>> re.findall( r'(<)?/s*(/w+@/w+)/s*(?(1)>)' , s )
[('<', 'usr1@mail1'), ('', 'usr2@maill2'), ('', 'usr3@mail3'), ('', 'usr4@mail4'), ('', 'usr5@mail5')]
它仍然找C所有的邮g地址?br />
惌实现q个功能Q单U的使用findall有点吃力Q需要用其它的一些函敎ͼ比如match或search函数Q再配合一些控制功能。这部分的内容将在下面详l讲解?br />
结Q以上基本上讲述了Python正则式的语法规则。虽然大部分语法规则看上去都很简单,可是E不注意Q仍然会得到与期望大相径庭的l果Q所以要写好正则式,需要仔l的?br />
会正则式规则的含义后不同规则之间l微的差别?br />
详细的了解了规则后,再配合后面就要介l的功能函数Q就能最大的发挥正则式的威力了?br />
2 re模块的基本函?br />
在上面的说明中,我们已经对re模块的基本函?#8216;findall’很熟悉了。当然如果光有findall的话Q很多功能是不能实现的。下面开始介l一下re模块其它的常用基本函数。灵z?br />
搭配使用q些函数Q才能充分发挥Python正则式的强大功能?br />
首先q是说下老熟人findall函数?br />
findall(rule , target [,flag] )
在目标字W串中查扄合规则的字符丌Ӏ?br />
W一个参数是规则Q第二个参数是目标字W串Q后面还可以跟一个规则选项Q选项功能在compile函数的说明中详细说明Q?br />
q回l果l果是一个列表,中间存放的是W合规则的字W串。如果没有符合规则的字符串被扑ֈQ就q回一个空列表?br />
2.1使用compile加?br />
compile( rule [,flag] )
正则规则编译成一个Pattern对象Q以供接下来使用?br />
W一个参数是规则式,W二个参数是规则选项?br />
q回一个Pattern对象
直接使用findall ( rule , target )的方式来匚w字符Ԍ一ơ两ơ没什么,如果是多ơ用的话,׃正则引擎每次都要把规则解释一遍,而规则的解释又是相当Ҏ间的Q?br />
所以这L效率很低了。如果要多次使用同一规则来进行匹配的话,可以使用re.compile函数来将规则预编译,使用~译q返回的Regular Expression Object或叫做Pattern?br />
象来q行查找?br />
?br />
>>> s='111,222,aaa,bbb,ccc333,444ddd'
>>> rule=r’/b/d+/b’
>>> compiled_rule=re.compile(rule)
>>> compiled_rule.findall(s)
['111', '222']
可见使用compileq的规则使用和未~译的用很怼。compile函数q可以指定一些规则标志,来指定一些特D选项。多个选项之间?#8217;|’Q位或)q接h?br />
I IGNORECASE 忽略大小写区别?br />
L LOCAL 字符集本地化。这个功能是Z支持多语a版本的字W集使用环境的,比如在{义符/wQ在英文环境下,它代表[a-zA-Z0-9]Q即所以英文字W和数字。如果在一个法
语环境下使用Q缺省设|下Q不能匹?é"?ç"。加上这L选项和就可以匚w了。不q这个对于中文环境似乎没有什么用Q它仍然不能匚w中文字符?br />
M MULTILINE 多行匚w。在q个模式?#8217;^’(代表字符串开??#8217;$’(代表字符串结?能够匹配多行的情况Q成首和行尾标记。比?br />
>>> s=’123 456/n789 012/n345 678’
>>> rc=re.compile(r’^/d+’) #匚w一个位于开头的数字Q没有用M选项
>>> rc.findall(s)
['123'] #l果只能扑ֈ位于W一个行首的’123’
>>> rcm=re.compile(r’^/d+’,re.M) #使用M选项
>>> rcm.findall(s)
['123', '789', '345'] #扑ֈ了三个行首的数字
同样Q对?#8217;$’来说Q没有用M选项Q它匹配最后一个行数字Q即’678’Q加上以后,p匚w三个行尾的数?56 012?78?
>>> rc=re.compile(r’/d+$’)
>>> rcm=re.compile(r’/d+$’,re.M)
>>> rc.findall(s)
['678']
>>> rcm.findall(s)
['456', '012', '678']
S DOTALL ‘.’号将匚w所有的字符。缺省情况下’.’匚w除换行符’/n’外的所有字W,使用q一选项以后Q?#8217;.’p匚w包括’/n’的Q何字W了?br />
U UNICODE /w,/W,/b,/B,/d,/D,/s?S都将使用Unicode?br />
X VERBOSE q个选项忽略规则表达式中的空白,q允怋?#8217;#’来引g个注释。这样可以让你把规则写得更美观些。比如你可以把规?br />>>> rc = re.compile(r"/d+|[a-zA-Z]+") #匚w一个数字或者单?br />
使用X选项写成Q?br />>>> rc = re.compile(r""" # start a rule/d+ # number| [a-zA-Z]+ # word""", re.VERBOSE)在这个模式下Q如果你惛_配一个空|你必?br />
?/ '的Ş式('/'后面跟一个空|
2.2 match与search
match( rule , targetString [,flag] )
search( rule , targetString [,flag] )
Q注Qre的match与search函数同compileq的Pattern对象的match与search函数的参数是不一L。Pattern对象的match与search函数更ؓ强大Q是真正最常用的函敎ͼ
按照规则在目标字W串中进行匹配?br />
W一个参数是正则规则Q第二个是目标字W串Q第三个是选项Q同compile函数的选项Q?br />
q回Q若成功q回一个Match对象Q失败无q回
findall虽然很直观,但是在进行更复杂的操作时Q就有些力不从心了。此时更多的使用的是match和search函数。他们的参数和findall是一LQ都是:
match( rule , targetString [,flag] )
search( rule , targetString [,flag] )
不过它们的返回不是一个简单的字符串列表,而是一个MatchObjectQ如果匹配成功的话).。通过操作q个matchObjectQ我们可以得到更多的信息?br />
需要注意的是,如果匚w不成功,它们则返回一个NoneType。所以在对匹配完的结果进行操作之前,你必需先判断一下是否匹配成功了Q比如:
>>> m=re.match( rule , target )
>>> if m: #必需先判断是否成?br />
doSomethin
q两个函数唯一的区别是Qmatch从字W串的开头开始匹配,如果开头位|没有匹配成功,qp|了;而search会蟩q开_l箋向后L是否有匹配的字符丌Ӏ针对不同的需
要,可以灉|使用q两个函数?br />
关于matchq回的MatchObject如果使用的问题,是Python正则式的_N所在,它与l的使用密切相关。我在下一部分详细讲解Q这里只举个最单的例子Q?br />
例:
>>> s= 'Tom:9527 , Sharry:0003'
>>> m=re.match( r'(?P<name>/w+):(?P<num>/d+)' , s )
>>> m.group()
'Tom:9527'
>>> m.groups()
('Tom', '9527')
>>> m.group(‘name’)
'Tom'
>>> m.group(‘num’)
'9527'
2.3 finditer
finditer( rule , target [,flag] )
参数同findall
q回一个P代器
finditer函数和findall函数的区别是Qfindallq回所有匹配的字符Ԍq存Z个列表,而finditer则ƈ不直接返回这些字W串Q而是q回一个P代器。关于P代器Q解释v?br />
有点复杂Q还是看看例子把Q?br />
>>> s=’111 222 333 444’
>>> for i in re.finditer(r’/d+’ , s ):
print i.group(),i.span() #打印每次得到的字W串和v始结束位|?br />
l果?br />
111 (0, 3)
222 (4, 7)
333 (8, 11)
444 (12, 15)
单的说吧Q就是finditerq回了一个可调用的对象,使用for i in finditer()的Ş式,可以一个一个的得到匚wq回的Match对象。这在对每次q回的对象进行比较复杂的操作
时比较有用?br />
2.4字符串的替换和修?br />
re模块q提供了对字W串的替换和修改函数Q他们比字符串对象提供的函数功能要强大一些。这几个函数?br />
sub ( rule , replace , target [,count] )
subn(rule , replace , target [,count] )
在目标字W串中规D则查扑配的字符Ԍ再把它们替换成指定的字符丌Ӏ你可以指定一个最多替换次敎ͼ否则替换所有的匚w到的字符丌Ӏ?br />
W一个参数是正则规则Q第二个参数是指定的用来替换的字W串Q第三个参数是目标字W串Q第四个参数是最多替换次数?br />
q两个函数的唯一区别是返回倹{?br />
subq回一个被替换的字W串
subq回一个元l,W一个元素是被替换的字符ԌW二个元素是一个数字,表明产生了多次替换?br />
例,下面字W串中的’dog’全部替换?#8217;cat’
>>> s=’ I have a dog , you have a dog , he have a dog ‘
>>> re.sub( r’dog’ , ‘cat’ , s )
' I have a cat , you have a cat , he have a cat '
如果我们只想替换前面两个Q则
>>> re.sub( r’dog’ , ‘cat’ , s , 2 )
' I have a cat , you have a cat , he have a dog '
或者我们想知道发生了多次替换Q则可以使用subn
>>> re.subn( r’dog’ , ‘cat’ , s )
(' I have a cat , you have a cat , he have a cat ', 3)
split( rule , target [,maxsplit] )
切片函数。用指定的正则规则在目标字W串中查扑配的字符Ԍ用它们作为分界,把字W串切片?br />
W一个参数是正则规则Q第二个参数是目标字W串Q第三个参数是最多切片次?br />
q回一个被切完的子字符串的列表
q个函数和str对象提供的split函数很相伹{D个例子,我们x上例中的字符串被’,’分割开Q同时要L逗号前后的空?br />
>>> s=’ I have a dog , you have a dog , he have a dog ‘
>>> re.split( ‘/s*,/s*’ , s )
[' I have a dog', 'you have a dog', 'he have a dog ']
l果很好。如果用str对象的split函数Q则׃我们不知?#8217;,’两边会有多少个空|而不得不对结果再q行一ơ处理?br />
escape( string )
q是个功能比较古怪的函数Q它的作用是字W串中的non-alphanumerics字符Q我已不知道该怎么译比较好了Q用反义字符的Ş式显C出来。有时候你可能希望在正则式中匹
配一个字W串Q不q里面含有很多re使用的符P你要一个一个的修改写法实在有点ȝQ你可以使用q个函数,
例在目标字符串s中匹?#8217;(*+?)’q个子字W串
>>> s= ‘111 222 (*+?) 333’
>>> rule= re.escape( r’(*+?)’ )
>>> print rule
/(/*/+/?/)
>>> re.findall( rule , s )
['(*+?)']
3 更深入的了解re的组与对?br />
前面对Python正则式的l进行了一些简单的介绍Q由于还没有介绍到match对象Q而组又是和match对象密切相关的,所以必d它们l合h介绍才能充分地说明它们的用途?br />
不过再详l介l它们之前,我觉得有必要先介l一下将规则~译后的生成的patter对象
3.1~译后的Pattern对象
一个正则式Q用compile函数~译Q不仅是Z提高匚w的速度Q同时还能用一些附加的功能。编译后的结果生成一个Pattern对象Q这个对象里面有很多函数Q他们看h
和re模块的函数非常象Q它同样有findall , match , search ,finditer , sub , subn , splitq些函数Q只不过它们的参数有些小的不同。一般说来,re模块函数的第一?br />
参数Q即正则规则不再需要了Q应则就包含在Pattern对象中了Q编译选项也不再需要了Q因为已l被~译q了。因此re模块中函数的q两个参数的位置Q就被后面的参数?br />
代了?br />
findall , match , search和finditerq几个函数的参数是一LQ除了少了规则和选项两个参数外,它们又加入了另外两个参数Q它们是Q查扑ּ始位|和查找l束位置Q也?br />
是说Q现在你可以指定查找的区_除去你不感兴的区间。它们现在的参数形式是:
findall ( targetString [, startPos [,endPos] ] )
finditer ( targetString [, startPos [,endPos] ] )
match ( targetString [, startPos [,endPos] ] )
search ( targetString [, startPos [,endPos] ] )
q些函数的用和re模块的同名函C用完全一栗所以就不多介绍了?br />
除了和re模块的函数同L函数外,Pattern对象q多了些东西Q它们是Q?br />
flags 查询~译时的选项
pattern查询~译时的规则
groupindex规则里的l?br />
q几个不是函敎ͼ而是一个倹{它们提供你一些规则的信息。比如下面这个例?br />
>>> p=re.compile( r'(?P<word>/b[a-z]+/b)|(?P<num>/b/d+/b)|(?P<id>/b[a-z_]+/w*/b)' , re.I )
>>> p.flags
2
>>> p.pattern
'(?P<word>//b[a-z]+//b)|(?P<num>//b//d+//b)|(?P<id>//b[a-z_]+//w*//b)'
>>> p.groupindex
{'num': 2, 'word': 1, 'id': 3}
我们来分析一下这个例子:q个正则式是匚w单词、或数字、或一个由字母?#8217;_’开_后面接字母或数字的一个ID。我们给q三U情늚规则都包入了一个命名组Q分别命?br />
?#8217;word’ , ‘num’?#8216;id’。我们规定大写不敏感,所以用了~译选项‘I’?br />
~译以后q回的对象ؓpQ通过p.flag我们可以查看~译时的选项Q不q它昄的不?#8217;I’Q而是一个数?。其实re.I是一个整敎ͼ2是它的倹{我们可以查看一下:
>>> re.I
2
>>> re.L
4
>>> re.M
8
…
每个选项都是一个数倹{?br />
通过p.pattern可以查看被编译的规则是什么。用print的话会更好看一?br />
>>> print p.pattern
(?P<word>/b[a-z]+/b)|(?P<num>/b/d+/b)|(?P<id>/b[a-z_]+/w*/b)
看,和我们输入的一栗?br />
接下来的p.groupindex则是一个字典,它包含了规则中的所有命名组。字典的key是名字,values是组的序受由于字典是以名字作为keyQ所以一个无命名的组不会出现在这里?br />
3.2l与Match对象
l与Match对象是Python正则式的重点。只有掌握了l和Match对象的用,才算是真正学会了Python正则式?br />
3.2.1 l的名字与序?br />
正则式中的每个组都有一个序P它是按定义时从左到右的顺序从1开始编L。其实,re的正则式q有一?LQ它是整个正则式本w?br />
我们来看个例?br />
>>> p=re.compile( r’(?P<name>[a-z]+)/s+(?P<age>/d+)/s+(?P<tel>/d+).*’ , re.I )
>>> p.groupindex
{'age': 2, 'tel': 3, 'name': 1}
>>> s=’Tom 24 88888888 <=’
>>> m=p.search(s)
>>> m.groups() #看看匚w的各l的情况
('Tom', '24', '8888888')
>>> m.group(‘name’) #使用l名获取匚w的字W串
‘Tom’
>>> m.group( 1 ) #使用l序可取匹配的字符Ԍ同用组名的效果一?br />
>>> m.group(0) # 0l里面是什么呢Q?br />
'Tom 24 88888888 <='
原来0l就是整个正则式,包括没有被包围到l里面的内容。当获取0l的时候,你可以不写这个参数。m.group(0)和m.group()的效果是一LQ?br />
>>> m.group()
'Tom 24 88888888 <='
接下来看看更多的Match对象的方法,看看我们能做些什么?br />
3.2.2 Match对象的方?br />
group([index|id]) 获取匚w的组Q缺省返回组0,也就是全部?br />
groups() q回全部的组
groupdict() q回以组名ؓkeyQ匹配的内容为values的字?br />
接上例:
>>> m.groupindex()
{'age': '24', 'tel': '88888888', 'name': 'Tom'}
start( [group] ) 获取匚w的组的开始位|?br />
end( [group] ) 获取匚w的组的结束位|?br />
span( [group] ) 获取匚w的组的(开始,l束Q位|?br />
expand( template )Ҏ一个模版用扑ֈ的内Ҏ换模版里的相应位|?br />
q个功能比较有趣Q它Ҏ一个模版来用匹配到的内Ҏ换模版中的相应位|,l成一个新的字W串q回。它使用/g<index|name>?index来指CZ个组?br />
接上?br />
>>> m.expand(r'name is /g<1> , age is /g<age> , tel is /3')
'name is Tom , age is 24 , tel is 88888888'
除了以上q些函数外,Match对象q有些属?br />
pos 搜烦开始的位置参数
endpos 搜烦l束的位|参?br />
q两个是使用findall或match{函数时Q传入的参数。在上面q个例子里,我们没有指定开始和l束位置Q那么缺省的开始位|就?,l束位置是最后?br />
>>> m.pos
0
>>> m.endpos
19
lastindex 最后匹配的l的序号
>>> m.lastindex
3
lastgroup 最后匹配的l名
>>> m.lastgroup
'tel'
re 产生q个匚w的Pattern对象Q可以认为是个逆引?br />
>>> m.re.pattern
'(?P<name>[a-z]+)//s+(?P<age>//d+)//s+(?P<tel>//d+).*'
得到了生这个匹配的规则
string 匚w的目标字W串
>>> m.string
'Tom 24 88888888 <='
转自:
http://hi.baidu.com/yangdaming1983/item/e6a8146255a5442169105b91