python 正则表达式高手在否?如何非贪婪的用 python split 分离如下文档

2016-11-10 01:11:38 +08:00
 xiyangyang

">"开头的那行是标题,下面 GGCA 之类的是数据。 需要把文档中所有的标题和数据提取出来,变成两个对应的数组或者 map 。 该如何写正则表达式呢?

p = re.compile(r'^\>.*?$')
clusters = re.split(p, content)

上面的代码总是不对,请高手出手看看。

>HSBGPG Human gene for bone gla protein (BGP) (this is name of sequence) GGCAGATTCCCCCTAGACCCGCCCGCACCATGGTCAGGCATGCCCCTCCTCATCGCTGGGCACAGCCCAGAGGGT ATAAACAGTGCTGGAGGCTGGCGGGGCAGGCCAGCTGAGTCCTGAGCAGCAGCCCAGCGCAGCCACCGAGACACC ATGAGAGCCCTCACACTCCTCGCCCTATTGGCCCTGGCCGCACTTTGCATCGCTGGCCAGGCAGGTGAGTGCCCC CACCTCCCCTCAGGCCGCATTGCAGTGGGGGCTGAGAGGAGGAAGCACCATGGCCCACCTCTTCTCACCCCTTTG >HSGLTH1 Human theta 1-globin gene CCACTGCACTCACCGCACCCGGCCAATTTTTGTGTTTTTAGTAGAGACTAAATACCATATAGTGAACACCTAAGA CGGGGGGCCTTGGATCCAGGGCGATTCAGAGGGCCCCGGTCGGAGCTGTCGGAGATTGAGCGCGCGCGGTCCCGG GATCTCCGACGAGGCCCTGGACCCCCGGGCGGCGAAGCTGCGGCGCGGCGCCCCCTGGAGGCCGCGGGACCCCTG GCCGGTCCGCGCAGGCGCAGCGGGGTCGCAGGGCGCGGCGGGTTCCAGCGCGGGGATGGCGCTGTCCGCGGAGGA CCGGGCGCTGGTGCGCGCCCTGTGGAAGAAGCTGGGCAGCAACGTCGGCGTCTACACGACAGAGGCCCTGGAAAG GTGCGGCAGGCTGGGCGCCCCCGCCCCCAGGGGCCCTCCCTCCCCAAGCCCCCCGGACGCGCCTCACCCACGTTC >comp0_c0_seq1 len=248 path=[418:0-247] TATGAGTCCATTATAACAGCCCTAGGACAAACCAGTAAAAAGAGATCTAGCAAAGAGAGT TGAGGGCATTTGTATCCAAGGCATTAAAACAGAGATTAAAGAGGATTTAAATAGAAATAT TTGATCCCGACAAATACCAAACTAGTAGATGCACCTAAATTAAATAAAGAGCTAGAAGGG

3528 次点击
所在节点    Python
13 条回复
eyp82
2016-11-10 02:03:39 +08:00
我不是 re 高手, 另外不清楚你的标题和数据的规则, 写了一个, 不知道是否是你想的样子:
r'>(.*?)\n([^>]*)'

上面的 pattern 假设:
1. 你的标题不强求>必须在每一行的开头(我上面的表达式, 没有在前面加^, 所以没在最开头出现的>也会匹配, 如果要求必须在行首, 可以试一下用 re.MULTILINE)
2. 你的数据里面不能包含>字符 (上面的正则表达式用>做为终止符, 遇到了就不再继续匹配了)
--------
如果发现了错误, 还请帮我指出来, 非常感谢各位.
eyp82
2016-11-10 02:06:31 +08:00
1. 上面的 re, 我没有在后面那个 match group 里把\n 单独拿出来, 如果你的数据里不想在最后有个\n, 可以把它单独写在()的外面 -->但我看你给的数据中间也是有换行的, 所以我猜其实没什么关系?
2. 这样转换出来是一个 tuple 的 list, 你用 dict comprehension 之类把它转换成 dict 就可以了
soratadori
2016-11-10 05:11:43 +08:00
。。。这个是 DNA ?
blueset
2016-11-10 06:26:39 +08:00
试着写了一下,上面的数据应该是没问题。

re.findall(">(.*?) ([ACGT ]+)(?= ?)", data)

偶数(含 0 )项是标题,奇数项是数据。
blueset
2016-11-10 06:33:56 +08:00
如果中间分割是换行符的话应该是这样的

re.findall(">(.*?)\n([ACGT\n]+)", a)
imn1
2016-11-10 07:35:26 +08:00
1.标题和数据怎样区分的?你的原文没有显示出来
2.数据区结尾就是下个标题的开始么?
3.为什么指定要非贪婪?作业?这个更应该用贪婪

In [6]: re.findall(r'>(?P<v>.*?)(?P<vv>[A-Z]{10}[^>]*)', content)
Out[6]:
[('HSBGPG Human gene for bone gla protein (BGP) (this is name of sequence) ',
'GGCAGATTCCCCCTAGACCCGCCCGCACCATGGTCAGGCATGCCCCTCCTCATCGCTGGGCACAGCCCAGAGGGT ATAAACAGTGCTGGAGGCTGGCGGGGCAGGCCAGCTGAGTCCTGAGCAGCAGCCCAGCGCAGCCACCGAGACACC ATGAGAGCCCTCACACTCCTCGCCCTATTGGCCCTGGCCGCACTTTGCATCGCTGGCCAGGCAGGTGAGTGCCCC CACCTCCCCTCAGGCCGCATTGCAGTGGGGGCTGAGAGGAGGAAGCACCATGGCCCACCTCTTCTCACCCCTTTG '),
('HSGLTH1 Human theta 1-globin gene ',
'CCACTGCACTCACCGCACCCGGCCAATTTTTGTGTTTTTAGTAGAGACTAAATACCATATAGTGAACACCTAAGA CGGGGGGCCTTGGATCCAGGGCGATTCAGAGGGCCCCGGTCGGAGCTGTCGGAGATTGAGCGCGCGCGGTCCCGG GATCTCCGACGAGGCCCTGGACCCCCGGGCGGCGAAGCTGCGGCGCGGCGCCCCCTGGAGGCCGCGGGACCCCTG GCCGGTCCGCGCAGGCGCAGCGGGGTCGCAGGGCGCGGCGGGTTCCAGCGCGGGGATGGCGCTGTCCGCGGAGGA CCGGGCGCTGGTGCGCGCCCTGTGGAAGAAGCTGGGCAGCAACGTCGGCGTCTACACGACAGAGGCCCTGGAAAG GTGCGGCAGGCTGGGCGCCCCCGCCCCCAGGGGCCCTCCCTCCCCAAGCCCCCCGGACGCGCCTCACCCACGTTC '),
('comp0_c0_seq1 len=248 path=[418:0-247] ',
'TATGAGTCCATTATAACAGCCCTAGGACAAACCAGTAAAAAGAGATCTAGCAAAGAGAGT TGAGGGCATTTGTATCCAAGGCATTAAAACAGAGATTAAAGAGGATTTAAATAGAAATAT TTGATCCCGACAAATACCAAACTAGTAGATGCACCTAAATTAAATAAAGAGCTAGAAGGG')]
注释:
1.(?P<变量名>...) 在 findall 中没意义,但在 match 中可以赋值
2.[A-Z]{10} 这个是标题与数据的分界,原题中没有明确规则,所以这里是随便找的,不通用;如果定下规则就取代这个
imn1
2016-11-10 08:05:47 +08:00
补充: findall 中不能使用两个非贪婪*模糊匹配,结果是不可预料的,我觉得这个算是 re 的 bug , php/js 同样写法是可以预期结果的
freestyle
2016-11-10 08:59:34 +08:00
把你的*替换成+就是非贪婪的了
```Python
p = re.compile(r'^\>.+?$')
clusters = re.split(p, content)
```
wjidea
2016-11-10 10:50:13 +08:00
遇到一只生物狗啊,握爪。

我觉得你可以用 itertools 里面的 groupby 来实现。

请看下面的 git-gist

<script src="https://gist.github.com/wjidea/1d26b6340384f3c2e6b2c22ff6425077.js"></script>
onlrrr
2016-11-10 11:28:44 +08:00
一个生物专业的大神从我背后路过让我回复 from Bio import SeqIO ,我什么都不知道。
czheo
2016-11-10 11:36:32 +08:00
cluster = {l[0]: l[1] for l in [s.strip().split("\n", 1) for s in content.split(">")] if len(l) == 2}
laoyur
2016-11-10 11:59:48 +08:00
楼主,你这个原文格式很重要啊,我复制下来粘贴到 sublime ,发现明明就是一行数据,用 re 来弄不太靠谱,因为中间的分隔符都是空格
你先以 > 进行 split ,拿到各个块,然后各块按空格 split ,最后一个分组就是你要的数据,之前的就是标题
hanbaobao2005
2016-11-10 14:02:11 +08:00
re.split() 的结果不会包含分割符,如果需要 titlte 和内容,建议使用 re.finditer, 然后再根据.start(), .end()获取相关的内容。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/319429

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX