2015-07-12 158 views
5

如何扩展下面的代码以允许我探索所有的情况下,我的子字符串和父字符串之间有2个不匹配或更少?字符串正则表达式两个不匹配Python

子串:SSQP

字符串到匹配于:SSPQQQQPSSSSQQQSSQPSPSQSSQPSSQPPSSSSQPSPSQSSQPSSSSQPSPSQSSQPSSSSQPSPSQ

这里是只有一个可能的失配引入的示例:

>>> s = 'SSPQQQQPSSSSQQQSSQPSPSQSSQPSSQPPSSSSQPSPSQSSQPSSSSQPSPSQSSQPSSSSQPSPSQ' 
>>> re.findall(r'(?=(SSQP|[A-Z]SQP|S[A-Z]QP|SS[A-Z]P|SSQ[A-Z]))', s) 
['SSQQ', 'SSQP', 'SSQP', 'SSQP', 'SSQP', 'SSQP', 'SSQP', 'SSQP', 'SSQP'] 

显然,结合有可能性在上面代码中的两个不匹配需要大量的蛮力打字的所有可能的组合。

如何扩展此代码(或重构此代码)以探究两个不匹配的可能性?

此外,我想修改我的输出,以便返回子字符串与字符串匹配的确切位置的数字索引(不是SSQQSSQP)。

回答

5

您不必使用re在这里你可以使用itertools模块而是节省大量的内存。

您可以先提取所有子串长度为4,然后将它们与你的substring比较,只是选择那些与你substring小于2的区别:

from itertools import izip,islice,tee 

def sub_findre(s,substring,diffnumber): 
    sublen=len(substring) 
    zip_gen=(izip(substring,islice(s,i,i+sublen)) for i in xrange(len(s))) 
    for z in zip_gen: 
     l,z=tee(z) 
     if sum(1 for i,j in l if i==j)>=sublen-diffnumber: 
      new=izip(*z) 
      next(new) 
      yield ''.join(next(new)) 

演示:

s='SSPQQQQPSSSSQQQSSQPSPSQSSQPSSQPPSSSSQPSPSQSSQPSSSSQPSPSQSSQPSSSSQPSPSQ' 

substring='SSQP' 
print list(sub_findre(s,substring,2)) 

['SSPQ', 'SPQQ', 'QQQP', 'SSSS', 'SSSQ', 'SSQQ', 'SQQQ', 'SSQP', 'PSQS', 'SSQP', 'SSQP', 'SQPP', 'SSSS', 'SSSQ', 'SSQP', 'PSQS', 'SSQP', 'SSSS', 'SSSQ', 'SSQP', 'PSQS', 'SSQP', 'SSSS', 'SSSQ', 'SSQP', 'PSQ'] 

如果您想要返回索引,您需要将索引放入izip,您可以使用itertools.repeat()重复长度为substring的索引:

from itertools import izip,islice,tee,repeat 

def sub_findre(s,substring,diffnumber): 
    sublen=len(substring) 
    zip_gen=(izip(substring,islice(s,i,i+sublen),repeat(i,sublen)) for i in xrange(len(s))) 
    for z in zip_gen: 
     l,z=tee(z) 
     if sum(1 for i,j,_ in l if i==j)>=sublen-diffnumber: 
      new=izip(*z) 
      next(new) 
      next(new) 
      yield next(new)[0] 

演示:

print list(sub_findre(s,substring,2)) 
[0, 1, 4, 8, 9, 10, 11, 15, 20, 23, 27, 28, 32, 33, 34, 39, 42, 46, 47, 48, 53, 56, 60, 61, 62, 67] 
+1

确实,正则表达式只是完全使用的错误工具。对于20个中的2个错误,模式中会有190个替代项。 –

+0

你能否返回索引号,类似于200_success的'match.start(0)'技巧? – warship

+0

@军舰签出编辑! – Kasramvd

2

组合爆炸不是对于四个中的两个不匹配不好。

首先,请注意,您可以省略SSQP本身,因为它涵盖了所有较宽松的情况。

re.findall(r'(?=([A-Z]SQP|S[A-Z]QP|SS[A-Z]P|SSQ[A-Z]))', s) 

所以,病例数是

   4! 
C(4, 1) = ––––––––––––– = 4 
      1! * (4 - 1)! 

对于最多两个错配,病例数是

   4! 
C(4, 2) = ––––––––––––– = 6 
      2! * (4 - 2)! 

即,

re.findall('(?=(SS..|S.Q.|S..P|.SQ.|.S.P|..QP))', s) 

(要简化了插图,我冒昧了。写.代替[A-Z]


要获得比赛的,而不是匹配的文本的位置:

[match.start(0) for match in re.finditer('(?=(SS..|S.Q.|S..P|.SQ.|.S.P|..QP))', s)] 
+0

我看到你在做什么,但我有子大如10个有时20个字母,有时甚至更多,这是非常难受,用're'规模模块。也许除了正则表达式之外,还有其他的东西可以使用吗?我喜欢你的“组合爆炸”的措辞,我会把这个术语放在我的兵工厂里:-) – warship

+1

那你为什么问C(4,2)这个问题而不是你真正想要的?你在谈论20个错误中有多少? –

+0

0,1或2长度为20的子字符串中的错误是可能的。联合写这样的东西是一种皇室的痛苦。在OP中,我只是想提供一个MWE。 – warship