標籤:perl
在處理文本時,常常遇到這樣的情況:就是我們需要把兩行文本做一個比較,然後選擇性輸出。而在while(<FILEHAND>){do something}程式塊中預設只能一次讀取一行。筆者在這裡,舉一個簡單的例子來說明怎麼處理這種情況。
有一個這樣一段文本:
a 1 2 3 4
a 5 6 7 8
a 6 7 8 9
a 7 8 9 11
a 7 8 9 12
a 13 12 14 15
a 18 14 16 17
a 2 3 4 65
要求是這樣的:如果上一行的第5列數字大於下一行第二列的數字,就把這兩行都輸出。
策略一:把輸入文本存放到數組中,然後利用for迴圈,一次輸出兩行做判斷。
指令碼如下:
#! /usr/bin/perl -wuse strict;chomp(my @a=<DATA>);my @out;for(my $i=0;$i<$#a;$i++){ my ($a1,$a2)=(split/\s+/,$a[$i])[1,4]; my ($b1,$b2)=(split/\s+/,$a[$i+1])[1,4]; push @out,@a[$i,$i+1] if $a2 > $b1;}my %ha;my @new=grep {$ha{$_}++<1}@out;print $_,"\n" [email protected];__DATA__a 1 2 3 4a 5 6 7 8a 6 7 8 9a 7 8 9 11a 7 8 9 12a 13 12 14 15a 18 14 16 17a 2 3 4 65
策略一思路比較簡單,但是如果輸入文本過大,比較消耗記憶體。當然使用Tie::File模組又是另外一回事情了。
在這裡,筆者利用tell和seek函數,對控制代碼定位做一下調整,就可以在while迴圈中,實現一次輸出多行,一行多次輸出了,是不是很方便呢?
代碼如下:
#! /usr/bin/perl -wuse strict;my @out;while(<DATA>){ chomp; my $pos=tell(DATA); my @a=split/\s+/,$_; my $sec=<DATA>; if($sec){ chomp$sec; my @b=split/\s+/,$sec; if($a[4]>$b[1]){ push @out,$_,$sec; } } seek(DATA,$pos,0);}my %ha;my @new=grep $ha{$_}++ < 1,@out;print $_,"\n" [email protected];__DATA__a 1 2 3 4a 5 6 7 8a 6 7 8 9a 7 8 9 11a 7 8 9 12a 13 12 14 15a 18 14 16 17a 2 3 4 65
程式啟動並執行結果如下:
a 5 6 7 8
a 6 7 8 9
a 7 8 9 11
a 7 8 9 12
a 18 14 16 17
a 2 3 4 65
__結束__