2012-10-22 31 views
0

我在下面有一個這樣的文件,其中以數字開頭的行是我的示例的ID,以下行是數據。如何比較在while循環內讀取的文件的兩行(如果它們相等或不相等)?

10001;02/07/98;;PI;M^12/12/59^F^^SP^09/12/55 
;;;;;M1|F1|SP1;9;9;9;9;9;9;;D16S539 
;;;;;M1|F1|SP1;9;9;9;9;9;9;;D7S820 
;;;;;M1|F1|SP1;9;9;9;9;9;9;;D13S317 
;;;;;M1|F1|SP1;9;9;9;9;9;9;;D5S818 
10002;02/07/98;;RJ;F^20/04/86^SP^ 
;;;;;F1|SP1;;;12;10;12;11;;D10S212 
;;;;;F1|SP1;;;8;8;10;8;;D7S820 
;;;;;F1|SP1;;;12;11;14;11;;D13S317 
;;;;;F1|SP1;;;13;12;13;8;;D5S818 

對於包含數據的線,我想測試的字段6-11是否是相同的,因爲我想要的數據,只有當他們是不等於彼此(在第一他們都是'9')。

所以我想分割線條並將它們存儲爲一個數組,然後將數組與〜運算符進行比較。但是,如果我正在讀取while循環內的文件並且每個行都重新定義了數組,我該怎麼做? 或者也許有更好的方法來做到這一點。

在此先感謝!

這是爲了說明我想做一個僞代碼:

open FILE, $ARGV[0] or die $!; 
while (<FILE>) { 
    chomp; 
    my @field = split /;/; 
    if ($field[0] eq '') { 
     if @fields[6 .. 11] is not equal to @fields[6 .. 11] in all the next lines { 
      do my calculation; 
     } 
    } 
} 
+0

你的意思是你想檢查** **所有的這些線是相同的,或者**任何**線是相同的? – TLP

+0

是的,我想檢查它們是否完全相同。 – vitor

+0

隨着ikegami的回答,似乎你只是想比較領域......當我問,你想比較*線*。這是什麼? – TLP

回答

3

我是正確地說,數據真正代表兩個記錄?如果是這樣,你想積累整條記錄的線路。

my @super_rec; 
while (<>) { 
    chomp; 
    my @fields = split /;/; 
    if ($fields[0] ne '') { 
     process_rec(\@super_rec) if @super_rec; 
     @super_rec = \@fields; 
    } else { 
     push @super_rec, \@fields; 
    } 
} 

process_rec(\@super_rec) if @super_rec; 

然後,你的問題可以回答。

sub process_rec { 
    my ($super_rec) = @_; 
    my ($rec, @subrecs) = @$super_rec; 

    my $do_calc = 0; 
    for my $i (1..$#subrecs) { 
     if ( $subrecs[0][ 6] ne $subrecs[$i][ 6] 
      || $subrecs[0][ 7] ne $subrecs[$i][ 7] 
      || $subrecs[0][ 8] ne $subrecs[$i][ 8] 
      || $subrecs[0][ 9] ne $subrecs[$i][ 9] 
      || $subrecs[0][10] ne $subrecs[$i][10] 
      || $subrecs[0][11] ne $subrecs[$i][11] 
     ) { 
      $do_calc = 1; 
      last; 
     } 
    } 

    if ($do_calc) { 
     ... 
    } 
} 
+0

嗨池上,謝謝。這非常複雜,因爲我是Perl的初學者,所以我在實際的代碼中遇到了一些麻煩。我應該在「if($ do_calc){}」部分中包含我的計算,但這不起作用,因爲此計算涉及循環遍歷文件(實際文件有數千條記錄)並使用字段(@fields)每行都要做一些計算。既然你已經在最初的while循環中遍歷了這個文件,我不能再做這個了。如果我再次打開該文件並再次拆分字段,那麼您的子程序似乎不起作用! – vitor

+0

當然這是因爲我不太瞭解子程序是如何工作的......我正在研究這個,我會再試一次。謝謝! – vitor

+0

它在完成讀取時每次爲每個「超級記錄」調用子,而不是在讀取整個文件之後。在您的示例數據中,有兩個「超級記錄」。 – ikegami

0

我假定你正在尋找跨線數據進行比較,不是單行線內。如果我弄錯了,請忽略我的答案。

我會這樣做的方式是重新將字段6到11作爲字符串加入。將數據從第一行保存爲$ firstdata,並將來自每個連續行的數據作爲$ nextdata進行比較。每次數據不匹配時,您就會啓動$差異計數器。當你得到一個ID行時,檢查以前的$差異是否大於零,如果是這樣做你的計算(你可能需要保存ID行和其他一些變量的其他領域)。然後重新初始化$差異和$ firstdata變量。

my $firstdata = ""; 
my $nextdata = ""; 
my $differences = 0; 
open FILE, $ARGV[0] or die $!; 
while (<FILE>) { 
    chomp; 
    my @field = split /;/; 
    if ($field[0] eq '') { 
     $nextdata = join(';', @fields[6..11]); 
     if ($firstdata && ($nextdata ne $firstdata)) { 
      $differences++; 
     } else { 
      $firstdata = $nextdata; 
     } 
    } else { 
     if ($differences) { 
      # do your calculation for previous ID 
     } 
     $firstdata = ""; 
     $differences = 0; 
    } 
} 
if ($differences) { 
    # do your calculation one last time for the last ID 
} 
0

這裏有一個方法可以做到這一點Regex。這可能是比其他方法效率低下,如果指數從6固定到11,被稱爲是那些只,因爲它會遍歷整個字符串: -

open FILE, $ARGV[0] or die $!; 
while (<FILE>) { 
    chomp; 
    my $num = 0; 
    my $same = 1; 
    while (/;(\d+);/) { 

     if ($num == 0) { $num = $1; } 
     elsif ($1 != $num) { $same = 0; last; } 

     # Substitute current digit matched with x (or any char) 
     # to avoid infinite loop 
     s/$1/x/; 
    } 

    if ($same) { 
     print "All digits same"; 
    } 
} 
+0

「true」和「false」不是perl概念,'break'關鍵字用於'switch'功能,而不是循環,你可能會想到「下一個」或「最後一個」 – TLP

+0

@TLP。哦!不知道,或者實際上忘了,我應該用什麼來代替真或假? –

+0

它不工作,但它可能看起來像它的工作,如果你沒有警告t呃。在Perl中,任何值爲0,undef空白字符串或空列表都是false。任何其他值是真實的。 – TLP

0

使用Text::CSV_XS模塊,你可以做這樣的事情:

use strict; 
use warnings; 
use Text::CSV_XS; 
use feature 'say'; 

my $csv = Text::CSV_XS->new({ 
     sep_char => ";", 
     binary  => 1, 
    }); 

my %data; 
my @hdrs; # store initial order of headers 
my $hdr; 
while (my $row = $csv->getline(*DATA)) { 
    if ($row->[0] =~ /^\d+$/) { 
     $csv->combine(@$row) or die "Cannot combine: " . 
      $csv->error_diag(); 
     $hdr = $csv->string(); # recreate the header 
     push @hdrs, $hdr;  # save list of headers 
    } else { 
     push @{ $data{$hdr} }, [ @{$row}[6..11] ]; 
    } 
} 

for (@hdrs) { 
    say "$_\n arrays are: " . (is_identical($data{$_}) ? "same":"diff"); 
} 

sub is_identical { 
    my $last; 
    for (@{$_[0]}) {   # argument is two-dimensional array 
     $last //= $_; 
     return 0 unless (@$_ ~~ @$last); 
    } 
    return 1;    # default = all arrays were identical 
} 


__DATA__ 
10001;02/07/98;;PI;M^12/12/59^F^^SP^09/12/55 
;;;;;M1|F1|SP1;9;9;9;9;9;9;;D16S539 
;;;;;M1|F1|SP1;9;9;9;9;9;9;;D7S820 
;;;;;M1|F1|SP1;9;9;9;9;9;9;;D13S317 
;;;;;M1|F1|SP1;9;9;9;9;9;9;;D5S818 
10002;02/07/98;;RJ;F^20/04/86^SP^ 
;;;;;F1|SP1;;;12;10;12;11;;D10S212 
;;;;;F1|SP1;;;8;8;10;8;;D7S820 
;;;;;F1|SP1;;;12;11;14;11;;D13S317 
;;;;;F1|SP1;;;13;12;13;8;;D5S818 

輸出:

10001;02/07/98;;PI;M^12/12/59^F^^SP^09/12/55 
    arrays are: same 
10002;02/07/98;;RJ;F^20/04/86^SP^ 
    arrays are: diff 
相關問題