在使用正则表达式,,去实现匹配,提取,查找所需的内容时,有时候,并不是所有的情况,都是可以通过单一的正则表达式实现的。
比如:
http://zhidao.baidu.com/question/498290393.html
中所希望的实现的,就是这类。
其是希望从字符串:
123ammmmmde234abc aaaaa 123ammmmmde234abc llll
“查找出 前面是数字的, 后面是字母的, 成对出现的单词 ”
此处即使用Python中的re.findall,通过单一的正则表达式,就一次性可以提取出来所需的:
[('ammmmmde', 'ammmmmde'), ('abc', 'abc')]
而即使去写对应的正则表达式,最接近于所希望的效果,也只能写出:
>>> re.findall(r'(?:\d+)([a-zA-Z]+).+?(\1)', 'sssa 123ammmmmde234abc aaaaa 123ammmmmde234abc llll') [('ammmmmde', 'ammmmmde')]
很明显,此处只能搜索出来第一组的ammmmmde,而无法一次性也同时提取出abc。
而实际上,深究起来,此处看似很简单的需求,实际上,是没法,通过单一的正则表达式,去实现一次性同时提取出ammmmmde和abc的。
下面就来解释一下,为何无法实现。
先解释,我们所希望的实现的是:
通过正则表达式:
r'(?:\d+)([a-zA-Z]+).+?(\1)'
先从
sssa 123ammmmmde234abc aaaaa 123ammmmmde |
中提取出:
(‘ammmmmde’, ‘ammmmmde’) |
再从
234abc aaaaa 123ammmmmde234abc |
中提取出:
(‘abc’, ‘abc’)] |
但是,实际上,由于正则表达式的搜索规则是:
从左到右,去搜索字符串,在其中,不管是否找到匹配的,都是对于搜索过的,没法回头,再去搜索。
即,对于原始的字符串:
sssa 123ammmmmde234abc aaaaa 123ammmmmde234abc llll |
从左到右,先是从
sssa 123ammmmmde234abc aaaaa 123ammmmmde |
中,的确是找到了,所希望的:
(‘ammmmmde’, ‘ammmmmde’) |
然后,接下来,就继续从剩下的字符串:
234abc llll |
中,去继续查找,是否有和此处的正则表达式:
r'(?:\d+)([a-zA-Z]+).+?(\1)'
所匹配的字符串,很明显,是没有匹配的,
所以结果,只找到了:
(‘ammmmmde’, ‘ammmmmde’) |
而没有找到:
(‘abc’, ‘abc’) |
究其原因,就是上面所说的,其中我们所希望的,匹配的的字符串:
sssa 123ammmmmde234abc aaaaa 123ammmmmde |
和
234abc aaaaa 123ammmmmde234abc |
中间重叠了,把两个放在一起比较,就容易看清楚了:
sssa 123ammmmmde234abc aaaaa 123ammmmmde 234abc aaaaa 123ammmmmde234abc llll
可以看到,其中的
234abc aaaaa 123ammmmmde |
是重叠了,而重叠的部分,对于正则表达式的搜索来说,就是在查找后半部分的ammmmmde时,所查找过了,
所以,后面没法再回头再利用,再查找重叠的:
234abc aaaaa 123ammmmmde |
所以,只从剩余的:
234abc llll |
中,当然无法查找到所需的两个abc的值了。
而,如果所要查找的字符串,对于下面的这种,所要匹配的两部分,没有重叠的话,则是可以一次性匹配出来两组内容的:
>>> re.findall(r'(?:\d+)([a-zA-Z]+).+?(\1)', 'sssa 123ammmmmde234 aaaaa 123ammmmmde456abc 234abc llll') [('ammmmmde', 'ammmmmde'), ('abc', 'abc')]
但是对于有人想说,对于最开始的例子,有重叠的部分的情况下,我就是想要找到所有的对应的多个组的内容,那怎么办呢?
对此,我开始是以为也没有什么好办法了,但是后来想到了一个,相对比较好的办法,具体做法如下:
#!/usr/bin/python # -*- coding: utf-8 -*- """ Function: 【总结】有些需要搜索的内容是重叠的,则使用单一的正则表达式是无法实现的 https://www.crifan.com/some_string_to_be_searched_is_overlap_so_can_not_implement_in_single_regular_expression Author: Crifan Li Version: 2012-11-17 """ #---------------------------------import--------------------------------------- import re; overlapStr = "sssa 123ammmmmde234abc aaaaa 123ammmmmde234abc llll"; searchPattern = r'(?:\d+)([a-zA-Z]+).+?(\1)'; foundFirstGroup = re.search(searchPattern, overlapStr); #print "foundFirstGroup=",foundFirstGroup; if(foundFirstGroup): expectedFirstTuple = re.findall(searchPattern, overlapStr); print "expectedFirstTuple=",expectedFirstTuple; #expectedFirstTuple= [('ammmmmde', 'ammmmmde')] firstGroupEndPos = foundFirstGroup.end(1); remainingStartPos = firstGroupEndPos; #print "remainingStartPos=",remainingStartPos; remainingStr = overlapStr[remainingStartPos:]; #print "remainingStr=",remainingStr; expectedSecondTuple = re.findall(searchPattern, remainingStr); print "expectedSecondTuple=",expectedSecondTuple; #expectedSecondTuple= [('abc', 'abc')]
【总结】
对于需要从原先字符串,通过复杂的正则表达式,去提取所需内容时,还是需要稍微注意一下,是否会出现此处特殊的,两部分内容有重叠,而导致单次无法提取全部的内容的情况的。
如果遇到有重叠的,则就需要去找其他办法解决了,比如上述的,先找第一个部分,再从第二个部分中,找所需的内容。