2015-08-14 48 views
1

善意解釋,爲什麼這個問題來
數據文件雖然使用嵌套perl grep輸出不同。爲什麼?

DATA----1 
DATA----2 
DATA----3 
DATA----4 
DATA----5 
DATA----6 
DATA----7 
SAMPLE----1 
SAMPLE----12 
SAMPLE----13 
SAMPLE----2 
SAMPLE----3 
SAMPLE----4 
SAMPLE----5 
OTHER----1 
OTHER----2 
OTHER----3 

,我需要與DATA樣品到一個數組中開始和另一個陣列應該具有啓動內容整條生產線與樣品結尾兩位數字

我已得到輸出與以下腳本

use strict; 
use warnings; 

open(FH, "di.txt"); 
my @file = <FH>; 
close(FH); 
my @arr2 = grep { $_ =~ m/^SAMPLE.+\d\d$/g } @file; ## this array prints 
my @arr1 = grep { $_ =~ m/^DATA|^SAMPLE/g } @file; 

print @arr1,"\n\t~~~~~~~~~~~\n\n",@arr2; 

首先當作使用

use strict; 
use warnings; 

open(FH, "di.txt"); 
my @file = <FH>; 
close(FH); 
my @arr1 = grep { $_ =~ m/^DATA|^SAMPLE/g } @file; 
my @arr2 = grep { $_ =~ m/^SAMPLE.+\d\d$/g } @file; ## this doesn't print 

print @arr1,"\n\t~~~~~~~~~~~\n\n",@arr2; 

同時運行此一個,只打印@arr1 會是什麼原因@arr2不打印

+0

對於我來說,您的兩個腳本都會給出相同的結果。沒有打印'@ arr2'。 – serenesat

+0

@Sant:只要在'\ d'後面移除'$',你就會得到所需的輸出保持數組的順序。 – serenesat

+0

總是使用3個參數來打開帶有詞法文件句柄和錯誤處理的文件。 '打開$ fh,「<」,「di.txt」或者「無法打開:$!」;' – serenesat

回答

4

的問題是,因爲全球的行爲在標量上下文中匹配/g選項

每個標量變量都有一個標記呃,它記得最近的全球比賽從哪裏開始,因此下一個比賽應該從哪裏開始搜索。它允許使用正則表達式中模式的\G錨,以及while循環這樣

my $s = 'aaabacad'; 

while ($s =~ /a(.)/g) { 
    print "$1 "; 
} 

它打印

a b c d 

事實上你不感興趣,在這個全球比賽的情況下,你只是想發現是否可以在字符串中找到該模式。該grep操作員施加標量上下文中的第一個參數,所以在使用/g選項,在該聲明中

my @arr1 = grep { $_ =~ m/^DATA|^SAMPLE/g } @file; 

DATASAMPLE後留下的@file設置爲正確標記的每一個元素。這意味着相同的元素m/^SAMPLE.+\d\d$/g會從那裏開始尋找並明確甚至無法找到^錨比賽的下一場比賽失敗

pos function,您可以訪問標記,您可以通過修復你的原代碼在第一次撥打grep之後將其重置爲字符串的開頭。如果你寫這個代替

my @arr1 = grep { $_ =~ m/^DATA|^SAMPLE/g } @file; 
pos($_) = 0 for @file; 
my @arr2 = grep { $_ =~ m/^SAMPLE.+\d\d$/g } @file; ## this doesn't print 

那麼輸出將是您的預期

正確的修改,但是,是寫你的意思,無論如何,這意味着從模式匹配,你應該刪除/g選項。此代碼也正常工作,它也更簡潔,更具可讀性,並且遠不易碎

my @arr1 = grep /^DATA|^SAMPLE/, @file; 
my @arr2 = grep /^SAMPLE.+\d\d$/, @file; 
+0

謝謝@Borodin。令人愉快的答案。我學會了pos函數pos($ _)的新實現。 – Sant

+1

@Sant:與其他許多內置運算符一樣,'pos'的默認參數是'$ _',所以'pos'與'pos($ _)'相同。但是你可以給它任何標量變量 – Borodin