2013-10-12 75 views
3

我正在嘗試使用Text::CSV Perl模塊來解析製表符分隔的文件。使用Text :: CSV解析Perl中的製表符分隔文件

我試圖解析的文件是:

#IGNORE COLUMN1 COLUMN2 COLUMN3 COLUMN4 
ROW1 x y z a 
ROW2 b c d 
ROW3 w 

注意該文件是製表符分隔。該文件可能有N列和N行。此外,在ROW2的情況下,它有第四個選項卡,但沒有值。在COLUMN1w值之後ROW3沒有標籤。即某些列可能有未定義的值或空白值。

到目前爲止,我已經開始寫一個Perl腳本,但在試圖找出如何我可以編寫代碼來回答以下問題都有所涉獵很早就:

瞭解多少ROWn有。然後爲每個COLUMNn檢查,看看我是否有ROWn值。因此,在這種情況下,COLUMN2,COLUMN3COLUMN4將缺少值。

任何提示和指導將有所幫助(我是Perl新手)。我已經看過CPAN Text :: CSV頁面,但我還沒有設法解決這個問題。

#!/usr/bin/perl 
use warnings; 
use strict; 
use v5.12; 
use Text::CSV; 

my $csv = Text::CSV->new ({ 
    escape_char   => '"', 
    sep_char   => '\t', 
    eol     => $\, 
    binary    => 1, 
    blank_is_undef  => 1, 
    empty_is_undef  => 1, 
    }); 

open (my $file, "<", "tabfile.txt") or die "cannot open: $!"; 
while (my $row = $csv->getline ($file)) { 
    say @$row[0]; 
} 
close($file); 
+0

如果你能同時擁有空字段(多個標籤成一排)和不存在的字段(線過早結束),你會算空字段一樣的非-existent? – TLP

+0

@TLP是的。基本上,一行可能有多個選項卡,其值爲「空白」(例如,在'ROW2'中,'COLUMN4'具有「空白」選項卡值或該行可能過早結束,就像在'ROW3'中那樣沒有字符'COLUMN1'中的'w'後 – user2402135

+2

使用'sep_char =>「\ t」'作爲''t''使得分隔符字面意思是'\ t'而不是製表符 – Kenosis

回答

0

一種方法,其中,每場各線工藝和遞增計數器時,它不是false

#!/usr/bin/env perl 

use warnings; 
use strict; 
use Text::CSV_XS; 

my (@col_counter); 
my ($line_counter, $r, $num_cols) = (0, 0, 0); 

open my $fh, '<', shift or die; 

my $csv = Text::CSV_XS->new({ 
    sep_char => qq|\t| 
}); 

while (my $row = $csv->getline($fh)) { 
    ## First row (header), get the number of columns. 
    if ($line_counter == 0) { 
     $num_cols = $#$row; 
     next; 
    } 
    ## For each data row, traverse every column and increment a 
    ## counter if it has any value. 
    for (1 .. $#$row) { 
     ++$col_counter[ $_ ] if $row->[ $_ ]; 
    } 
} 
continue { 
    $line_counter++; 
} 

printf qq|Lines of file: %d\n|, $line_counter - 1; 
## Check if any column has missing values. For each column compare the 
## number of lines read (substract 1 of header) with its counter. If they 
## are different it means that the column had any row without value. 
for my $i (1 .. $num_cols) { 
    $r = $line_counter - 1 - (defined $col_counter[ $i ] ? $col_counter[ $i ] : 0); 
    if ($r > 0) { 
     printf qq|Column %d has %d missing values\n|, $i, $r; 
    } 
} 

有了您的數據。例如,運行它想:

perl script.pl infile 

國債收益率:

Lines of file: 3 
Column 2 has 1 missing values 
Column 3 has 1 missing values 
Column 4 has 2 missing values 

UPDATE:請參閱註釋。我進行反向查找不包含任何值的列,並將當前行號附加到數組,並使用join來提取所有行。

我更換了哪些零件?這裏節省行號。

for (1 .. $num_cols) { 
    push @{ $col_counter[ $_ ] }, $line_counter unless $row->[ $_ ]; 
} 

在這裏打印它們。您需要評論舊的行爲。

if (defined $col_counter[ $i ]) { 
    printf qq|Column %d has no value in lines %s\n|, $i, join q|,|, @{ $col_counter[ $i ] }; 
} 

它產生:

Lines of file: 3 
Column 2 has no value in lines 3 
Column 3 has no value in lines 3 
Column 4 has no value in lines 2,3 
+0

這段代碼似乎不工作時,我的文件看起來像這樣: '#IGNORE \t COLUMN1 \t COLUMN2 \t欄3 \t COLUMN4 ROW1 \t X \t X \t X row2.' 它是不知道2個值丟失了'COLUMN4' – user2402135

+0

@ user2402135:在你的輸入文件'column4'有兩個遺漏值。我不明白你的榜樣。 – Birei

+0

如果我改變上面的輸入文件,使得'COLUMN4'沒有任何行值,那麼當打印缺失值時忽略整列。我希望能夠打印出'COLUMN4'有'N'缺少值,如果它有零值。目前,如果代碼完全沒有值,代碼將忽略「COLUMN4」。 – user2402135