【问题标题】:Extract lines containing specific words提取包含特定单词的行
【发布时间】:2022-01-22 12:59:33
【问题描述】:

输入:

ID   aa
AA   Homo sapiens
DR   ac
BB   ad
FT   ae
//
ID   ba
AA   mouse
DR   bc
BB   bd
FT   be
//
ID   ca
AA   Homo sapiens
DR   cc
BB   cd
FT   ce
//

预期输出:

DR   ac
FT   ae
//
DR   cc
FT   ce
//

代码:

word = 'Homo sapiens'
with open(input_file, 'r') as txtin, open(output_file, 'w') as txtout:
    
    for block in txtin.read().split('//\n'):   # reading a file in blocks
        if word in block:   # extracted block containing the word, 'Homo sapiens'
            extracted_block = block + '//\n'

            for line in extracted_block.strip().split('\n'):   # divide each block into lines
                if line.startswith('DR   '):
                    dr = line 

                elif line.startswith('FT   '):
                    ft = line

我根据“//”(块)读取输入文件。而且,如果块中包含“智人”一词,我提取了块。此外,在该块中,以“DR”开头的行定义为 dr,以“FT”开头的行定义为 ft。我应该如何使用 dr 和 ft 编写“输出”以获得“预期输出”?

【问题讨论】:

    标签: python parsing line block word


    【解决方案1】:

    您可以编写一个带有标志的简单解析器。总之,当您到达带有 AA 和单词的行时,将标志设置为 True 以保留以下感兴趣的字段,直到您到达块结束时,在这种情况下您重置标志。

    word = 'Homo sapiens'
    
    with open(input_file, 'r') as txtin, open(output_file, 'w') as txtout:
        keep = False
        for line in txtin:
            if keep and line.startswith(('DR', 'FT', '//')):
                txtout.write(line)
            if line.startswith('//'):
                keep = False # reset the flag on record end
            elif line.startswith('AA') and word in line:
                keep = True
    

    输出:

    DR   ac
    FT   ae
    //
    DR   cc
    FT   ce
    //
    

    注意。这要求 AA 在要保存的字段之前。如果没有,您必须使用类似的逻辑逐块解析(将数据保存在内存中)

    【讨论】:

      【解决方案2】:

      如果您对基于正则表达式的解决方案持开放态度,那么一种选择是将整个文件读入字符串,然后使用re.findall

      with open(input_file, 'r') as file:
          inp = file.read()
      
      matches = re.findall(r'(?<=//\n)ID.*?\nAA\s+Homo sapiens\n(DR\s+\w+\n)BB\s+\w+\n(FT\s+\w+\n//\n?)', '//\n' + inp)
      for match in matches:
          for line in match:
              print(line, end='')
      

      打印出来:

      DR   ac
      FT   ae
      //
      DR   cc
      FT   ce
      //
      

      这是一个demo,表明该模式可以正确识别每个匹配块中的块和 DR/FT 行。

      【讨论】:

      • 如果您不想使用正则表达式,那么您将不得不编写一个基本的 parser 来逐行逐块进行。我认为这个答案也可能会让您感到困惑。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多