我想分割一个字符重复两次的序列,并保留分离部分。是否有一个较短的正则表达式?
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
答案 0 :(得分:4)
使用itertools.groupby
代替正则表达式:
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']
答案 1 :(得分:1)
使用re.findall
:
>>> import re
>>> seq='tgtttccgagtgacccgagatagaaacttaccgga'
>>> [m[0] for m in re.findall(r'((?:(.)(?!\2)|(.)\3\3+)+|..)', seq)]
['tgttt', 'cc', 'gagtgacccgagatagaaac', 'tt', 'a', 'cc', 'gg', 'a']
主要思想是编写一个始终成功的模式,这样,正则表达式引擎不必使用4个替代方法(aa,cc,gg,tt +环顾四周)来测试字符串中的每个位置,而大多数情况下时间。所有比赛都是连续的。
模式有两个部分,第一个(?:(.)(?!\2)|(.)\3\3+)+
描述了不完全是两个相同字符(单个字符(.)(?!\2)
或两个以上相同字符(.)\3\3+
)的所有内容,并重复了贪婪地将第二部分与..
如果需要,可以用[actg]
替换所有点。
与re.finditer
:
[mo.group(0) for mo in re.finditer(r'(?:(.)(?!\1)|(.)\2\2+)+|..', seq)]
或从Python 3.6开始:
[mo[0] for mo in re.finditer(r'(?:(.)(?!\1)|(.)\2\2+)+|..', seq)]