我想拆分一个字符重复两次的序列,并保留分隔部分。有一个较短的正则表达式吗?
In [101]: seq='tgtttccgagtgacccgagatagaaacttaccgga'
In [102]: l=[ s for s in re.split(r"(?<!a)(a{2})(?!a)|(?<!g)(g{2})(?!g)|(?<!c)(c{2})(?!c)|(?<!t)(t{2})(?!t)",seq) if s ]
In [103]: l
Out[103]: ['tgttt', 'cc', 'gagtgacccgagatagaaac', 'tt', 'a', 'cc', 'gg', 'a']
In [104]: ''.join(l)==seq
Out[104]: True
使用itertools.groupby
:而不是regex
import itertools
def get_combos(d):
for a, b in d:
if a:
yield from b
else:
yield ''.join(b)
seq='tgtttccgagtgacccgagatagaaacttaccgga'
new_seq = [''.join(b) for _, b in itertools.groupby(seq)]
final_result = list(get_combos([[a, list(b)] for a, b in itertools.groupby(new_seq, key=lambda x:len(x) == 2 and x[0] == x[1])]))
输出:
['tgttt', 'cc', 'gagtgacccgagatagaaac', 'tt', 'a', 'cc', 'gg', 'a']
使用re.findall
:
>>> import re
>>> seq='tgtttccgagtgacccgagatagaaacttaccgga'
>>> [m[0] for m in re.findall(r'((?:(.)(?!2)|(.)33+)+|..)', seq)]
['tgttt', 'cc', 'gagtgacccgagatagaaac', 'tt', 'a', 'cc', 'gg', 'a']
其主要思想是编写一个始终成功的模式,这样,正则表达式引擎就不必在大多数情况下用4个备选方案(aa、cc、gg、tt+查找(来测试字符串中的每个位置。所有的比赛都是连续的。
该模式有两个部分,第一个(?:(.)(?!2)|(.)33+)+
描述了所有不是完全相同的两个字符(单个字符(.)(?!2)
或两个以上相同的字符(.)33+
(并且贪婪地重复,第二部分将剩余的情况与..
相匹配
如果需要,可以随意将所有点替换为[actg]
。
re.finditer
:
[mo.group(0) for mo in re.finditer(r'(?:(.)(?!1)|(.)22+)+|..', seq)]
或者从Python 3.6开始:
[mo[0] for mo in re.finditer(r'(?:(.)(?!1)|(.)22+)+|..', seq)]