2013-04-30 48 views
1

我想找出一种方法来做到这一点,我知道它应该是可能的。首先有一点背景。解析CSV文件,找到列并记住它们

我想自动创建用于将DNA序列提交给GenBank的NCBI Sequin块的过程。我总是最终创建一个表,列出物种名称,样品ID值,序列类型以及最终收集的位置。我很容易将它导出到制表符分隔的文件中。现在我做这样的事情:

while ($csv) { 
    foreach ($_) { 
    if ($_ =! m/table|species|accession/i) { 
     @csv = split('\t', $csv); 
     print NEWFILE ">[species=$csv[0]] [molecule=DNA] [moltype=genomic] [country=$csv[2]] [spec-id=$csv[1]]\n"; 
    } 
    else { 
     next; 
    } 
    } 
} 

我知道这是凌乱的,我只是输入了类似于我有记忆的东西(没有脚本的任我在家里的电脑,只在工作)。

现在对我罚款,因为现在我知道哪些列我需要的信息(种类,位置和ID号)在工作。

但是,有没有办法(必须有)对我来说,动态找到所需信息的列?也就是说,无论列的顺序如何,来自正确列的正确信息都会发送到正确的地方?

第一行通常是表格X(其中X是出版物中表格的编号),下一行通常会有感兴趣的列标题,并且在标题中几乎是通用的。几乎所有的表格都会有标准标题来搜索,我可以使用|在我的模式匹配。

回答

1

创建一个列标题映射到列数的哈希:

my %columns; 
... 

if (/table|species|accession/i) { 
    my @headings = split('\t'); 
    my $col = 0; 
    foreach my $col (@headings) { 
    $columns{"\L$col"} = $col++; 
    } 
} 

然后你可以使用$csv[$columns{'species'}]

3

首先,如果我不推荐优秀的Text::CSV_XS模块,我会失职;它在读取CSV文件方面做得更加可靠,甚至可以处理Barmar提到的列映射方案。

也就是说,Barmar有正确的方法,尽管它完全忽略了“表格X”行是单独的行。我建议采取一个明确的办法,也许这样的事情(这都将有一些详细信息只是为了把事情说清楚,我可能会更紧密地把它写在生产代码):

# Assumes the file has been opened and that the filehandle is stored in $csv_fh. 
# Get header information first. 

my $hdr_data = {}; 

while(<$csv_fh>) { 
    if(! $hdr_data->{'table'} && /Table (\d+)/) { 
    $hdr_data->{'table'} = $1; 
    next; 
    } 
    if(! $hdr_data->{'species'} && /species/) { 
    my $n = 0; 
    # Takes the column headers as they come, creating 
    # a map between the column name and column number. 
    # Assumes that column names are case-insensitively 
    # unique. 
    my %columns = map { lc($_) => $n++ } split(/\t/); 
    # Now pick out exactly the columns we want. 
    foreach my $thingy (qw{ species accession country }) { 
     $hdr_data->{$thingy} = $columns{$thingy}; 
    } 
    last; 
    } 
} 

# Now process the rest of the lines. 

while(<$csv_fh>) { 
    my $col = split(/\t/); 
    printf NEWFILE ">[species=%s] [molecule=DNA] [moltype=genomic] [country=%s] [spec-id=%s]\n", 
    $col[$hdr_data->{'species'}], 
    $col[$hdr_data->{'country'}], 
    $col[$hdr_data->{'accession'}]; 
} 

的一些变化这会让你接近你所需要的东西。

+0

突出显示%列和%{$ hdr_data}的主要原因是因为您的标题更具灵活性。例如,'keys%{$ hdr_data}'总是会让你知道你感兴趣的列的名字, $ hdr_data - > {'bogus'}将始终返回undef,即使数据中有'假'列。把你的数据精简到你需要的数据总是最好的。 – mcglk 2013-04-30 03:35:51

+0

如果您需要处理引用或转义,Text :: CSV是非常好的,但如果您确定不需要,它会过度杀伤。制表符分隔的文件通常不会使用;他们只是不允许带有标签的字段。 – cjm 2013-04-30 06:04:56

+0

你能指点我一个网站或书籍,它对映射机制有很好的解释吗?我是一位了解perl的生物学家,几乎无法完成我想要的任务,但我对这些问题缺乏深入的了解。我有o'reilly的学习perl,掌握perl,编程Perl,开始perl生物信息学,掌握生物信息学的perl,以及其他一些书。〜alphaa – AlphaA 2013-05-01 18:33:13