解析CSV文件,查找列并记住它们

时间:2013-04-30 02:19:59

标签: perl csv

我想找到一种方法来做到这一点,我知道它应该是可能的。首先是一点背景。

我想自动创建NCBI Sequin块的过程,以便将DNA序列提交给GenBank。我总是最终创建一个表格,列出物种名称,标本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是出版物中表的编号),下一行通常会有感兴趣的列标题,并且几乎是标题中的通用。几乎所有的表都有标准的标题来搜索,我可以使用|在我的模式匹配。

2 个答案:

答案 0 :(得分:3)

首先,如果我不推荐优秀的Text::CSV_XS模块,那将是我的疏忽;它可以更加可靠地读取CSV文件,甚至可以处理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'}];
}

一些变化将使您接近所需。

答案 1 :(得分: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'}]