2012-04-18 107 views
1

我目前通過REGEX行匹配表格行中的文件中的表提取值。來自IF語句正則表達式匹配的值(Perl)

foreach my $line (split("\n", $file)) { 
    if ($line =~ /^(\S+)\s*(\S+)\s*(\S+)$/) { 
     my ($val1, $val2, $val3) = ($1, $2, $3); 

     # $val's used here 
    } 
} 

我特意爲代碼中的清晰度分配了vals。我的一些錶行中包含10個vals(又名列) - 是否有一種更有效的方法來分配val而不是執行... =($ 1,$ 2,...,$ n)?

+0

http://stackoverflow.com/questions/2304577/how-can-i-store-regex-captures-in-an-array-in-perl? – Scroog1 2012-04-18 14:47:39

+2

我總是喜歡http://stackoverflow.com/questions/874915/perl-extracting-data-from-text-using-regex他們使用拆分 - 你的正則表達式似乎是一個候選人。 – Konerak 2012-04-18 14:47:41

回答

8

列表上下文中的匹配產生捕獲組的列表。如果失敗,則返回一個空列表,該列表爲false。您可以因此

if(my ($val1, $val2, $val3) = $line =~ m/^(\S+)\s*(\S+)\s*(\S+)$/) { 
    ... 
} 

但是,在此代碼中顯示一些紅色標誌。該正則表達式捕獲看起來非常類似於一個拆分:

if(my ($val2, $val2, $val3) = split ' ', $line) { 
    ... 
} 

其次,爲什麼要通過換行分割$ file;如果你正在閱讀一個文件的內容,遠遠更好的是實際讀取一行一次:

while(my $line = <$fh>) { 
    ... 
} 
+0

而不是'split'''我傾向於使用'split/\ s + /' – 2012-04-18 14:56:00

+1

@LeonardoHerrera爲什麼?如果存在領先的空白區,它所做的就是保留一個前導空字段。 – TLP 2012-04-18 15:02:31

+0

要小心交換拆分的正則表達式,它們不是兩個都意味着同樣的事情,考慮如果'$ line ='abc def'會產生什麼結果;' – 2012-04-18 15:18:06

1

看起來你只是用一個空間表delimiter.You可以使用split功能:

@valuearray = split(" ", $line)

然後處理元件:

@valuearray[0] ,@valuearray[1]等。

+0

感謝您的輸入。我提供的例子很簡單 - 我的報告中的分隔符實際上並不一致。 – kaspnord 2012-04-18 15:44:51

+0

@kaspnord split支持完整的正則表達式。您可以使用任何分隔符,甚至可以在同一個表中使用不同的分隔符。 – byrondrossos 2012-04-18 18:13:34

2

我認爲這是不實際的代碼,因爲如果是這樣,它不會工作:

foreach my $line (split("\n", $file)) { 
    if ($line =~ /^(\S+)\s*(\S+)\s*(\S+)$/) { 
     my ($val1, $val2, $val3) = ($1, $2, $3); 
    } 
# all the $valX variables are now out of scope 
} 

你也應該知道,\s*也將匹配空字符串,並可能導致細微的錯誤。例如:

"a bug" =~ /^(\S+)\s*(\S+)\s*(\S+)$/; 
# the captures are now: $1 = "a"; $2 = "bu"; $3 = "g" 

即使盡管\S+是貪婪的,錨^ ... $將迫使正則表達式來適應,因此允許空字符串分割的話。

如果您的意圖是捕獲由空格分隔的所有單詞,那麼使用split是您的最佳選擇,正如其他人已經提到的那樣。

open my $fh, "<", "file.txt" or die $!; 
my @stored; 
while (<$fh>) { 
    my @vals = split; 
    push(@stored, \@vals) if @vals; # ignore empty values 
} 

這會將任何捕獲的值存儲到二維數組中。直接使用文件句柄和逐行讀取是首選方法,除非由於某種原因,您實際上需要將整個文件存儲在內存中。

+0

感謝您的輸入。我已經更新了這個問題,以澄清$ val變量的範圍。你的例子中的'split'是否處理不同數量的空白?不幸的是,我不能用你的例子明確地命名vals。看到我對LeoNerd的帖子關於文件處理的評論。 – kaspnord 2012-04-18 15:49:59

+0

@kaspnord是的,分割成一個數組將會保存任何數量的匹配。儘管如果空白的數量是一個問題,例如如果「a \ t \ tc」應該是'$ val1 =「a」; $ val3 =「c」'(跳過'$ val2'),然後否。但是,你可能會更好地使用CSV模塊。如果你不知道需要的變量的數量,你可以使用一個數組。如果您覺得有必要,您可以輕鬆地對您的數組元素進行計數並稍後將其分配給指定的變量。啜食文件可能沒有必要(通常​​不會),並會降低性能。但那是另一個問題。 – TLP 2012-04-18 16:11:46