如何清洗列数不一致的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
相关产品推荐
相关产品推荐

