['55555', '666666']
>>> re.findall( r?\\b\\d{1,4}\\b? , s ) # 4位数以下的数 ['1', '22', '333', '4444']
‘*?’ ‘+?’ ‘??’ 最小匹配
?*? ?+? ???通常都是尽可能多的匹配字符。有时候我们希望它尽可能少的匹配。比如一个c语言的注释 ? ?,如果使用最大规则: >>> s =r ? code ?
>>> re.findall( r?/\\*.*\\*/? , s ) [? code ?]
结果把整个字符串都包括进去了。如果把规则改写成
>>> re.findall( r?/\\*.*?\\*/? , s ) #在*后面加上?,表示尽可能少的匹配 ['', '']
结果正确的匹配出了注释里的内容
1.3 前向界定与后向界定
有时候需要匹配一个跟在特定内容后面的或者在特定内容前面的字符串,Python提供一个简便的前向界定和后向界定功能,或者叫前导指定和跟从指定功能。它们是:
‘(?<=…)’ 前向界定
括号中?…?代表你希望匹配的字符串的前面应该出现的字符串。 ‘(?=…)’ 后向界定
括号中的?…?代表你希望匹配的字符串后面应该出现的字符串。
例: 你希望找出c语言的注释中的内容,它们是包含在??之间,不过你并不希望匹配的结果把??也包括进来,那么你可以这样用: >>> s=r? code ?
>>> re.findall( r?(?<=/\\*).+?(?=\\*/)? , s ) [' comment 1 ', ' comment 2 ']
注意这里我们仍然使用了最小匹配,以避免把整个字符串给匹配进去了。 要注意的是,前向界定括号中的表达式必须是常值,也即你不可以在前向界定的括号里写正则式。比如你如果在下面的字符串中想找到被字母夹在中间的数字,你不可以用前向界定: 例:
>>> s = ?aaa111aaa , bbb222 , 333ccc ?
>>> re.findall( r?(?<=[a-z]+)\\d+(?=[a-z]+)' , s ) # 错误的用法 它会给出一个错误信息:
error: look-behind requires fixed-width pattern
不过如果你只要找出后面接着有字母的数字,你可以在后向界定写正则式: >>> re.findall( r?\\d+(?=[a-z]+)?, s )
['111', '333']
如果你一定要匹配包夹在字母中间的数字,你可以使用组(group)的方式 >>> re.findall (r'[a-z]+(\\d+)[a-z]+' , s ) ['111']
组的使用将在后面详细讲解。
除了前向界定前向界定和后向界定外,还有前向非界定和后向非界定,它的写法为:
‘(?
只有当你希望的字符串前面不是’?’的内容时才匹配 ‘(?!...)’后向非界定
只有当你希望的字符串后面不跟着?…?内容时才匹配。 接上例,希望匹配后面不跟着字母的数字 >>> re.findall( r?\\d+(?!\\w+)? , s ) ['222']
注意这里我们使用了\\w而不是像上面那样用[a-z],因为如果这样写的话,结果会是:
>>> re.findall( r?\\d+(?![a-z]+)? , s ) ['11', '222', '33']
这和我们期望的似乎有点不一样。它的原因,是因为?111?和?222?中的前两个数字也是满足这个要求的。因此可看出,正则式的使用还是要相当小心的,因为我开始就是这样写的,看到结果后才明白过来。不过Python试验起来很方便,这也是脚本语言的一大优点,可以一步一步的试验,快速得到结果,而不用经过烦琐的编译、链接过程。也因此学习Python就要多试,跌跌撞撞的走过来,虽然曲折,却也很有乐趣。
1.4 组的基本知识
上面我们已经看过了Python的正则式的很多基本用法。不过如果仅仅是上面那些规则的话,还是有很多情况下会非常麻烦,比如上面在讲前向界定和后向界定时,取夹在字母中间的数字的例子。用前面讲过的规则都很难达到目的,但是用了组以后就很简单了。 ‘(‘’)’ 无命名组
最基本的组是由一对圆括号括起来的正则式。比如上面匹配包夹在字母中间的数字的例子中使用的(\\d+),我们再回顾一下这个例子: >>> s = ?aaa111aaa , bbb222 , 333ccc ? >>> re.findall (r'[a-z]+(\\d+)[a-z]+' , s ) ['111']
可以看到findall函数只返回了包含在’()’中的内容,而虽然前面和后面的内容都匹配成功了,却并不包含在结果中。
除了最基本的形式外,我们还可以给组起个名字,它的形式是

