最新消息:20210816 当前crifan.com域名已被污染,为防止失联,请关注(页面右下角的)公众号

【总结】有些需要搜索的内容是重叠的,则使用单一的正则表达式是无法实现的

RegularExpression crifan 4092浏览 0评论

在使用正则表达式,,去实现匹配,提取,查找所需的内容时,有时候,并不是所有的情况,都是可以通过单一的正则表达式实现的。

比如:

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')]

 

【总结】

对于需要从原先字符串,通过复杂的正则表达式,去提取所需内容时,还是需要稍微注意一下,是否会出现此处特殊的,两部分内容有重叠,而导致单次无法提取全部的内容的情况的。

如果遇到有重叠的,则就需要去找其他办法解决了,比如上述的,先找第一个部分,再从第二个部分中,找所需的内容。

转载请注明:在路上 » 【总结】有些需要搜索的内容是重叠的,则使用单一的正则表达式是无法实现的

发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
89 queries in 0.208 seconds, using 22.16MB memory