如何从python多行文本中的匹配行中获取内部文本?

时间:2018-11-16 02:27:18

标签: python

我有一个名为test.txt的文本文件。我想从test.txt抓起以>lcl开头的行,然后提取locus标记后和右括号]中的值。我想对location之后的值做同样的事情。我想要的结果如下所示。如何在python中执行此操作?

所需结果

SS1G_08319  <504653..>506706
SS1G_12233  complement(<502136..>503461)
SS1G_02099  <2692251..>2693298
SS1G_05227  complement(<1032740..>1033620)

test.txt

>lcl|NW_001820825.1_gene_208 [locus_tag=SS1G_08319] [db_xref=GeneID:5486863] [partial=5',3'] [location=<504653..>506706] [gbkey=Gene]
ATGGGCAAAGCTTCTAGGAATAAGACGAAGCATCGCGCTGATCCTACCGCAAAAACTGTTAAGCCACCCA
CTGACCCAGAGCTTGCAGCAATTCGAGTTAACAAAATTCTGCCAATTCTCCAAGATTTACAAAGTGCAGA
CCAGTCAAAGAGATCAACTGCTGCAACTGCCATTGCGAACCTCGTTGACGATACAAAATGTCGAAAGTTA
TTCTTGAGAGAGCAAATTGTTCGTATTCTACTCGAACAAACCCTTACAGACTCAAGCATGGAAACTAGAA
>lcl|NW_001820817.1_gene_205 [locus_tag=SS1G_12233] [db_xref=GeneID:5483157] [partial=5',3'] [location=complement(<502136..>503461)] [gbkey=Gene]
ATGATCTGTAATACGCTCGGTGTTCCACCCTGCAACAGAATTCTTAAGAAATTCTCCGTTGGCGAGAGTC
GTCTCGAAATTCAAGACTCAGTACGAGGCAAAGATGTCTACATCATTCAATCGGGTGGAGGAAAGGCCAA
TGATCACTTCGTGGATCTTTGCATTATGATCTCCGCATGCAAAACTGGCTCTGCCAAGCGCGTCACTGTC
GTCCTTCCTTTGTTTCCTTATTCACGACAACCTGATCTGCCATACAACAAGATTGGCGCACCACTTGCCA
>lcl|NW_001820834.1_gene_1034 [locus_tag=SS1G_02099] [db_xref=GeneID:5493612] [partial=5',3'] [location=<2692251..>2693298] [gbkey=Gene]
ATGGCTTCTGTTTACAAGTCATTATCAAAGACCTCTGGTCATAAAGAAGAAACCCCGACTGGTGTCAAGA
AAAACAAGCAAAGAGTTTTGATCTTGTCTTCAAGAGGAATAACTTACAGGTATATAAATTTGTACCGATG
CGATGCAAAAAATCGCAGGAAAATGCTAACTCTACAACTTAGACATCGACATCTCCTCAATGACCTTGCG
TCCCTACTTCCCCACGGTAGGAAAGATGCGAAACTCGATACCAAGTCAAAGCTTTATCAATTGAATGAAT
>lcl|NW_001820830.1_gene_400 [locus_tag=SS1G_05227] [db_xref=GeneID:5489764] [partial=5',3'] [location=complement(<1032740..>1033620)] [gbkey=Gene]
ATGGCGGACGGATGTAAGTTAATTGATGTTCCTACTATTCCAGACTAATATTTGTTCTCGTCCCTACAAT
GCATTCGGAACGGATGGTACTCAGTTAACTTTGTAACTAATACAACGTCTAGTAAATGACCAAAGAACTG

我是python的新手,所以我想出了类似这样的东西:

results = []
f = open("test.txt", 'r')

while True:
    line = f.readline()
    if not line:
        break
    file_name = line.split("locus_tag")[-1].strip()
    f.readline()  # skip line 
    data_seq1 = f.readline().strip()
    f.readline()  
    data_seq2 = f.readline().strip()
    results.append((file_name, data_seq1))

2 个答案:

答案 0 :(得分:4)

我认为,解决此问题的最简单的方法是使用regex,例如以下示例:

import re

results = []
# Open the file in the 'read' mode
# with statement will take care to close the file
with open('YOUR_FILE_PATH', 'r') as f_file:
    # Read the entire file as a one string
    data = f_file.read()
    # Here we search for the string that begins with '>lcl'
    # and in which we find the [locus_tag=...] and [localtion=...]
    results = re.findall(r'>lcl.*\[locus_tag=(.*?)\].*\[location=(.*?)\]', data)

for locus, location in results:
    print(locus, location)

输出:

SS1G_08319 <504653..>506706
SS1G_12233 complement(<502136..>503461)
SS1G_02099 <2692251..>2693298
SS1G_05227 complement(<1032740..>1033620)

使用dict作为结果并通过分割行的另一种形式:

import re

results = {}
with open('fichier1', 'r') as f_file:
    # Here we split the file's lines into a list
    data = f_file.readlines()
    for line in data:
        # Here we search for the lines that begins by '>lcl'
        # and same as the first attempt
        results.update(re.findall(r'^>lcl.*\[locus_tag=(.*?)\].*\[location=(.*?)\]', line))

for locus, location in results.items():
    print(locus, location)

编辑:创建一个DataFrame并将其导出到csv文件中:

import re
from pandas import DataFrame as df

results = {}
with open('fichier1', 'r') as f_file:
    data = f_file.readlines()
    for line in data:
        results.update(re.findall(
            r'^>lcl.*\[locus_tag=(.*?)\].*\[location=(.*?)\]',
            line
        ))

df_ = df(
    list(results.items()),
    index=range(1, len(results) + 1),
    columns=['locus', 'location']
)
print(df_)
df_.to_csv('results.csv', sep=',')

它将打印并创建一个名为results.csv的文件:

        locus                        location
1  SS1G_12233    complement(<502136..>503461)
2  SS1G_08319                <504653..>506706
3  SS1G_05227  complement(<1032740..>1033620)
4  SS1G_02099              <2692251..>2693298

答案 1 :(得分:2)

我想提出两种替代解决方案。一种将使用正则表达式提取行上的任何命名标签集,另一种则是完整的琐事,但显示了一种无需正则表达式的方式。

通用正则表达式解决方案

execute_process(COMMAND some system command
    OUTPUT_VARIABLE command_output
)

# ... nothing happens for a few minutes while the process executes

# All of the output from the past few minutes is printed all at once.
message(STATUS ${command_output})

此函数返回一个由您感兴趣的标签作为关键字的字典列表,您将像这样使用它:

PersistableAdapter  pa = new PersistableAdapter (product,null,null,null);
pa.load("isImageChanged");
System.out.println("Value is:: "+ pa.get("isImageChanged"));

您可以使用结果来获取所需的确切打印输出:

import re

def get_tags(filename, tags, prefix='>lcl'):
    tags = set(tags)
    pattern = re.compile(r'\[(.+?)=(.+?)\]')

    def parse_line(line):
        return {m.group(1): m.group(2) for m in pattern.finditer(line) if m.group(1) in tags}

    with open(filename) as f:
        return [parse_line(line) for line in f if prefix is None or line.startswith(prefix)]

其优点是您可以使用以后选择的结果,并配置要提取的标签。

没有正则表达式解决方案

此版本只是我写的要显示的内容。请不要模仿它,因为代码是毫无意义的维护负担。

tags = ['locus_tag', 'location']
result = get_tags('test.txt', tags)

此函数的行为与第一个函数相同,但是相比之下,解析函数是一个混乱局面。它的鲁棒性也要差很多,例如因为假设您所有的方括号或多或少都匹配。

这是一个显示两个方法的IDEOne链接:https://ideone.com/X2LKqL