You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何清洗列数不一致的TSV文件?Python/Perl是否比Bash更合适?

TSV文件清洗:提取ID与分类学信息

需求说明

原始TSV内容(字段用制表符分隔):

BCM92732.1  sialidase   Abditibacteriota    bacterium
VTR99890.1  sialidase   :   Sialidase   Precursor   OS=Rhodopirellula   baltica (strain SH1)    GN=RB3353   PE=4    SV=1:   BNR_2   Tuwongella  immobilis
QEL17956.1  putative    retaining   sialidase   Limnoglobus roseus
AMV31440.1  Sialidase   precursor   Pirellula   sp. SH-Sr6A

需要清洗后保留每行的ID(第一个字段),以及末尾的分类学名称,结果如下:

BCM92732.1 Abditibacteriota bacterium
VTR99890.1 Tuwongella   immobilis
QEL17956.1 Limnoglobus  roseus
AMV31440.1 Pirellula    sp. SH-Sr6A

因为每行字段数不一致,没法直接按固定列数截取,下面提供几种不同语言的实现方案:


Bash(awk实现)

利用awk处理每行的字段数组,从后往前遍历,跳过带=、:的注释字段和功能描述字段,直到找到分类学字段的起始位置,然后输出ID加后续字段:

awk '{
    printf "%s", $1;
    # 从最后一个字段往前找,跳过带特殊符号的注释字段
    for (i=NF; i>=2; i--) {
        if ($i !~ /[:=]/ && $i !~ /sialidase|putative|retaining|precursor|Precursor|BNR_2/) {
            # 找到起始位置后,从i到NF的字段都输出
            for (j=i; j<=NF; j++) {
                printf "\t%s", $j;
            }
            break;
        }
    }
    printf "\n";
}' input.tsv > output.tsv

Python实现

读取文件每行,分割成字段列表,先保留第一个ID,然后从后往前筛选字段,排除带特殊符号和功能关键词的内容,最后拼接输出:

import sys

# 定义需要排除的功能/注释关键词
exclude_words = {'sialidase', 'putative', 'retaining', 'precursor', 'Precursor', 'BNR_2'}

with open(sys.argv[1], 'r') as f, open('output.tsv', 'w') as out:
    for line in f:
        line = line.strip()
        if not line:
            continue
        fields = line.split('\t')
        id_field = fields[0]
        # 从后往前找分类字段的起始索引
        tax_start = len(fields) - 1
        while tax_start >= 1:
            field = fields[tax_start]
            if ':' in field or '=' in field or field in exclude_words:
                tax_start -= 1
            else:
                break
        # 拼接分类字段
        tax_fields = fields[tax_start:]
        out.write(f"{id_field}\t{'\t'.join(tax_fields)}\n")

运行方式:python3 clean_tsv.py input.tsv

Perl实现

和awk思路类似,分割每行成数组,从后往前筛选有效分类字段,然后输出:

#!/usr/bin/perl
use strict;
use warnings;

my %exclude = map { $_ => 1 } qw(sialidase putative retaining precursor Precursor BNR_2);

open my $in, '<', $ARGV[0] or die $!;
open my $out, '>', 'output.tsv' or die $!;

while (my $line = <$in>) {
    chomp $line;
    next if $line =~ /^\s*$/;
    my @fields = split /\t/, $line;
    my $id = shift @fields;
    # 从后往前找有效字段
    my @tax;
    for (reverse @fields) {
        if (/[:=]/ || exists $exclude{$_}) {
            next;
        } else {
            unshift @tax, $_;
        }
    }
    print $out join("\t", $id, @tax), "\n";
}

close $in;
close $out;

运行方式:perl clean_tsv.pl input.tsv


内容的提问来源于stack exchange,提问作者Someone_1313

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 22:27:31