2009-02-25 60 views
-2

我想在if條件中擴展字符串$searchCriteria。任何線索?如何擴展Perl字符串中的變量?

use strict; 

my $argNum; 
my $searchCriteria = ""; 
foreach $argNum (0 .. $#ARGV) { 
    $searchCriteria = $searchCriteria . "(\$_ =~ \/" . $ARGV[$argNum] . "\/i) && "; 
} 
$searchCriteria =~ s/&& $//; 
#print $searchCriteria; 

open IP, "<vm.txt" or die $!; 

my @fileContents = <IP>; 
foreach (@fileContents) { 
    if (${$searchCriteria}) { 
     print $_; 
    } 
} 
+0

你想完成什麼?該代碼的重點是什麼? – 2009-02-25 19:34:20

+0

@brian:看起來他想要評估它。 – Axeman 2009-02-25 20:24:18

回答

1

看起來要EVAL行是否包含在@ARGV所有參數。

我認爲這可能更符合你所尋找的內容,也更適合perl人羣。

use FileHandle; 
use List::MoreUtil qw<all>; 

my @regexes = map { qr/\L$_\E/i } @ARGV; 

my $fh = FileHandle->new('<vm.txt'); 
die "Err: $!" unless $fh; 

foreach my $line (<$fh>) { 
    print $line if all { $line =~ m/$_/i } @regexes; 
} 

當然,如果你想要一些壓縮,因爲你要在一個單一的執行再次執行測試時間和時間,你可以創建一個子。

sub create_compound_test { 
    my $test_sub_text = "sub (_) {\n local \$_ = shift;"; 

    foreach my $arg (map { lc; } @_) { 
     $test_sub_text .= "\n return unless m/$arg/i;"; 
    } 
    $test_sub_text .= "\n return 1;\n}"; 

    my $test_sub = eval $test_sub_text; 
    Carp::croak "Could not create test:\n $test_sub_text - [email protected]" if [email protected]; 
    return $test_sub; 
} 

它做同樣的事情$_ =~ /blah/i && $_ =~ /blah2/ ...

那麼這將是:

my $match_all = create_compound_test(@ARGV); 
foreach (<$fh>) { 
    print if $match_all->(); 
} 

但我可能會更容易做到這一點:

my $match_all = create_compound_test(@ARGV); 
foreach (grep { $match_all->(); } <$fh>) { 
    print; 
} 

...或甚至...

print foreach grep { $match_all->(); } <$fh>; 
1

呃... ...我不知道問題是什麼......但不知何故,我懷疑你需要的QR //表達式(報價正則表達式)。

0

你的問題是什麼?也許你正在尋找ack?這似乎是你試圖eval一個字符串(通常是一個壞主意)。你至少應該使用qr //。可能是這樣的:

my @regexs = map qr/(?i)$_/, @ARGV; 
my $search = sub { 
    for my $re (@regexes) { 
    return unless /$re/; 
    } 
    return 1; 
} 
open IP, "<", "vm.txt" or die "Err: $!"; 
while (<IP>) { 
    print $_ if $search->(); 
} 

這可以很容易地改善。它沒有經過測試。因人而異。

3

如果您的搜索條件是正則表達式,您應該準備自己編譯的正則表達式。還要注意使用while循環(當讀取文件時)以避免過多的內存使用。如果你想包含任何參數的行:

use strict; 
use warnings; 

my $searchRe = do { 
    my $searchCriteria = join '|', map "(?:$_)", @ARGV; 
    qr/$searchCriteria/i; 
}; 

open my $fh, '<', 'vm.txt' or die $!; 

while (<$fh>) { 
    print if m/$searchRe/; 
} 

close $fh; 

,或者如果你想包含所有的人行:

use strict; 
use warnings; 

my $searcher = do { 
    my @searchCriteria = map qr/$_/i, @ARGV; 
    sub { 
    # study; # study can help for long lines or lot of regular expressions 
    for my $re (@searchCriteria) { 
     return unless m/$re/; 
    } 
    return 1 
    } 
}; 

open my $fh, '<', 'vm.txt' or die $!; 

while (<$fh>) { 
    print if $searcher->(); 
} 

close $fh; 

(請注意,你可能要繞$_如果命令行一個\Q\E參數是字符串而不是正則表達式。)

最後,如果您希望提高許多搜索條件的速度,請使用Regexp::Optimizer

use Regexp::Optimizer; 

my $searchRe = do { 
    my $searchCriteria = join '|', map "(?:$_)", @ARGV; 
    Regexp::Optimizer->new->optimize(qr($searchCriteria)i); 
}; 
0

如果參數不是正則表達式,你可以構造一個可以工作的正則表達式。

的想法是按以下順序:

  1. 交替(one|two|...)
  2. 其次是非貪婪任何(.*?)
  3. 其次是什麼匹配交替#負前瞻1 (?!\1)
  4. 其次重複交替(one|two|...)
  5. 後面是非貪婪的東西(.*?)
  6. 其次是什麼匹配任何最後的交替(?!\1|\2)

重複4-6的交替的負向前查找,直到我們對所有方面的匹配。

這樣構造此代碼是:

sub create_compound_match { 

    my @args   = @_; 
    my $arg_limit  = $#args; 
    my $expr   = join('|', map { lc; } @args); 
    my $neg_lookahead = join('|', map { "\\$_" } 1..$arg_limit); 

    my $test = join('.*?' 
        , "($expr)" 
        , (map { '(?!' 
          . substr($neg_lookahead, 0, 3 * $_ - 1) 
          . ")($expr)" 
          } 1..$arg_limit 
        ) 
        ); 

    return qr/$test/i; 
} 

這會以這種方式進行測試:

my $test = create_compound_match(@ARGV); 
print foreach grep { /$test/i } <$fh>; 

然而,這種缺乏對正則表達式來傳遞命令行@ARGV上的能力可以等於qw,並且生成的正則表達式將愉快地匹配'aa aaa aaaa',而不需要匹配b*,因爲「aa」!=「a」,所以負面預測得到滿足。

0

看完Taking from Hynek -Pichi- Vychodil's answer之後,我意識到你可以用List :: MoreUtil的all子例程大大簡化整個任務。我強烈推薦這個軟件包。

use strict; 
use warinings; 
use List::MoreUtil qw/all/; # if installed (not a bad idea to get it if not) 

my @regexen = map { qr/$_/i } @ARGV; 

open my $fh, '<', 'vm.txt' or die $!; 

foreach my $line (<$fh>) { 
    print $line if all { $line =~ $_ } @regexen; 
}; 

close $fh; 

替補多allany一個 「或」 基於匹配。

編輯:媽的,看起來像Axeman發佈了一些非常相似的東西。偉大的思想都一樣,呃? :)

相關問題