我正在尝试解决一个可以最简单建模的问题如下。
我有大量的字母序列。这些字母来自两个列表:(1)成员列表(2)非成员列表。序列具有不同的组成和长度(例如AQFG,CCPFAKXZ,HBODCSL等)。我的目标是当任何“成员”跟随任何两个“非成员”后,将数字“1”插入这些序列中:
Rule 1: Insert '1' after the first member letter that is followed
by 2 or more non-members letters.
Rule 2: Insert not more than one '1' per sequence.
The 'Members': A, B, C, D
'Non-members': E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z
换句话说,一旦成员函后面跟着2个非成员字母,就插入一个'1'。总的来说,每个序列只插入一个'1'。我想要实现的目的是:
AQFG ---> A1QFG
CCPFAKXZ ---> CC1PFAKXZ
BDDCCA ---> BDDCCA1
HBODCSL ---> HBODC1SL
ABFCC ---> ABFCC
ACKTBB ---> AC1KTBB # there is no '1' to be inserted after BB
我认为代码将是这样的:
members = ['A','B','C','D']
non_members = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N',
'O','P','Q','R','S','T','U','V','W','X','Y','Z']
strings = ['AQFG', 'CCPFAKXZ', 'BDDCCA', 'HBODCSL', 'ABFCC']
for i in members:
if i in strings:
if member is followed by 2 non-members: # Struggling here
i.insert(index_member, '1')
return i
return ''
编辑
我发现一个解决方案可能是使用itertools.permutations(non_members, 2)
生成两个“非成员”项目的所有排列列表,然后测试它们在字符串中的存在。
但这个问题有更优雅的解决方案吗?
答案 0 :(得分:0)
生成所有排列将会爆炸您正在检查的内容。你需要改变迭代的方式:
members = ...
non_members = ...
s = 'AQFG'
out = ""
look = 2
for i in range(len(s)-look):
out += s[i]
if (s[i] in members) & \
(s[i+1] in non_members) & \
(s[i+2] in non_members):
out += '1' + s[i+1:]
break
通过这种方式,您只需要遍历目标字符串一次,并且您不需要生成排列,这种方法可以扩展到比您的方法更多的前瞻。
答案 1 :(得分:0)
我相信也可以通过正则表达式完成。
s = 'AQFG'
x = re.sub(r'([ABCD])([EFGHIJKLMNOPQRSTUVWXYZ])',r'\g<1>1\2',s)
print(x)
这将打印A1QFG
答案 2 :(得分:0)
对不起。我错过了。 re.sub可以使用一个可选的count参数,该参数可以在给定的替换次数后停止。
{{1}}
这将打印HB1ODCSL