0

我有一个登录号和 16S rrna 序列的文件,我想做的是删除所有 RNA 行,只保留带有登录号和物种名称的行(并删除中间的所有垃圾)。所以我的输入文件看起来像这样(在登录号前面有 > ):

> D50541 1 1409 1409bp rna Abiotrophia defiva Aerococcaceae
CUGGCGGCGU GCCUAAUACA UGCAAGUCGA ACCGAAGCAU CUUCGGAUGC UUAGUGGCGA ACGGGUGAGU AACACGUAGA UAACCUACCC UAGACUCGAG GAUAACUCCG GGAAACUGGA GCUAAUACUG GAUAAUGGAUAU AGAGAUAAUU UCUUUU...

> AY538167 1 1411 1411bp rna Acholeplasma hippikon Acholeplasmataceae
CUGGCGGCGU GCCUAAUACA UGCAAGUCGA ACGCUCUAUA GCAAUAUAGG GAGUGGCGAA CGGGUGAGUA ACACGUAGAU AACCUACCCU UACUUCGAGG AUAACUUCGG GAAACUGGAG CUAAUACUGG AUAGGUCAUA UUGAGAUGCAUC UUA ...

我希望我的输出看起来像这样:

>D50541 Abiotrophia defectiva Aerococcaceae

>AY538167 Acholeplasma hippikon Acholeplasmataceae

我写的代码做了我想要的……对于大多数行。它看起来像这样:

    #!/usr/bin/env python

    # take LTPs111.compressed fasta and reduce to accession numbers with names.
    import re
    infilename = 'LTPs111.compressed.fasta'
    outfilename = 'acs.fasta'

    regex = re.compile(r'(>)\s(\w+).+[rna]\s+([A-Z].+)')    

    #remove extra letters and spaces
    with open(infilename, 'r') as infile, open(outfilename, 'w') as outfile:
        for line in infile:
            x = regex.sub(r'\1\2 \3', line)
    #remove rna sequences
        for line in x:
            if '>' in line:
                outfile.write(x)

有时,代码似乎跳过了一些名称。例如,对于上面的第一个入藏号,我只回来了:

>D50541 气球菌科

为什么我的代码会这样做?每个入藏号的输入看起来相同,并且每行的“rna”和名字之间的间距相同(5 个空格)。

感谢任何可能有想法的人!

4

2 回答 2

2

我仍然无法运行您的代码以获得声称的结果,但我想我知道问题出在哪里:

>>> line = '> AY538167 1 1411 1411bp rna Acholeplasma hippikon Acholeplasmataceae'
>>> regex = re.compile(r'(>)\s(\w+).+[rna]\s+([A-Z].+)')
>>> regex.findall(line)
[('>', 'AY538167', 'Acholeplasmataceae')]

问题是[rna]\s+匹配任何一个字符 r, n, 或a在单词的末尾。而且,因为所有匹配都是贪婪的,没有前瞻或其他任何东西来阻止它,这意味着它匹配n.hippikon

简单的解决方案是删除括号,使其匹配字符串 rna

>>> regex = re.compile(r'(>)\s(\w+).+rna\s+([A-Z].+)')

如果您的任何物种或属可以以该字符串结尾,那将不起作用。有没有这样的名字?如果是这样,您需要想出一个更好的方法来描述1409bp零件和rna零件之间的截止点。最简单的可能是只寻找rna被空格包围的:

>>> regex = re.compile(r'(>)\s(\w+).+\s+rna\s+([A-Z].+)')

这是否真的正确,我不能在不了解格式的情况下说,但希望您了解我做得足够好以验证它是否正确(或者至少提出比我能问的更聪明的问题)。


添加捕获组可能有助于调试事物。例如,而不是这个:

(>)\s(\w+).+[rna]\s+([A-Z].+)

……搜索这个:

(>)(\s)(\w+)(.+[rna]\s+)([A-Z].+)

显然,您想要的捕获组现在\1\3 \5不是\1\2 \3……但最重要的是您可以看到匹配的内容\4

[('>', ' ', 'AY538167', ' 1 1411 1411bp Acholeplasma hippikon ', 'Acholeplasmataceae')]

所以,现在的问题是“为什么.+[rna]\s+匹配'1 1411 1411bp Acholeplasma hippikon '?有时上下文很重要,但在这种情况下,它并不重要。您不希望该组在任何上下文中匹配该字符串,但它总是会匹配它,所以那是您必须调试的部分。


此外,可视化的正则表达式浏览器通常也有很大帮助。最好的可以为表达式的部分内容和匹配的文本等着色,以向您展示正则表达式如何以及为什么这样做。

当然,您会受到那些在您的平台上或在线上运行并使用 Python 语法的限制。如果您小心和/或只使用简单的功能(如您的示例中),perl/PCRE 语法非常接近 Python,并且 JavaScript/ActionScript 也非常接近(要记住的一大区别是替换/ sub 使用$而不是\1)。

我没有一个很好的在线推荐,但快速浏览一下Debuggex看起来很酷。

于 2013-05-06T18:47:36.823 回答
0

括号之间的项目是字符类,因此通过将正则表达式设置为查找“[rna]”,您请求的行包含r、n 或 a,但不是全部三个。

此外,如果您想要的所有行都具有“bp rna”模式,我会用它来拉出这些行。通过逐行读取文件,以下内容对我来说适用于快速而肮脏的 line-yanker,例如:

regex = re.compile(r'^[\w\s]+bp rna .*$')

但是,再一次,如果它像在其中查找带有“bp rna”的行一样简单,您可以逐行读取文件并完全放弃正则表达式:

for line in file:
   if "bp rna" in line:
     print(line) 

编辑:我没有仔细阅读请求而搞砸了。也许捕获和替换正则表达式会有所帮助?

for line in file:
  if "bp rna" in line:
    subreg = re.sub(r'^(>[\w]+)\s[\d\s]+bp\srna\s([\w\s]+$)', r"\1 \2", line)
    print(subreg)

输出:

>AY538166 Acholeplasma granularum Acholeplasmataceae

>AY538167 Acholeplasma hippikon Acholeplasmataceae

这应该匹配您想要的内容之间的任何空格(制表符或空格)。

于 2013-05-06T18:56:23.713 回答