2009-02-25 14 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

何を達成しようとしていますか?そのコードのポイントは何ですか? –

+0

@brian:それは彼がそれを評価したいと思うように見えます。 – Axeman

+0

ええ、なぜですか?どのようにするかを尋ねることは、しばしば間違った質問です。私は彼が達成しようとしていることを知りたい。 –

答えて

1

あなたはラインが@ARGVですべての引数が含まれているかどうかをevalにしたいように見えます。

これはあなたが探しているもののラインに沿っているかもしれないと思うし、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->(); 
} 

これを容易に向上させることができました。それはテストされていません。 YMMV。

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

FWIW、私はPerlの正規表現エンジンがこれらすべての最適化を自動的に処理すると思います。 – jrockway

+0

これは、||を使用して複合テストを作成していた場合に機能します。しかし、彼は&& => "$ _ =〜/ term_one/i && $ _ =〜/ term_two/&& ..."を使用しています – Axeman

+0

投稿された質問の混乱の美しい、美しい翻訳。名声。 –

0

引数が正規表現でない場合に動作する単一の正規表現を構築することができます。

アイデアは、以下の配列である。

  1. 交互に続く交番#1 (?!\1)
  2. にマッチしたものの否定先読みが続く非欲張り何(.*?)
  3. 続い(one|two|...)
  4. 繰り返される交代(one|two|...)
  5. それに続く貪欲でないもの私たちは、すべての条件に一致するものを持ってまで、最後の交番(?!\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"!= "a"なので、b*の一致を必要とせずに、aaaaaaaaaにうまく一致するので、否定的な先読みが満たされます。

  • 0

    Taking from Hynek -Pichi- Vychodil's answerを見てから、List :: MoreUtilのallサブルーチンを使ってこの作業全体を大幅に簡略化できることに気付きました。私はこのパッケージを強く勧めます。 "または" ベースの一致のためにanyall Subsitute

    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; 
    

    編集:まあ、Axemanのように見えますが、これに非常に似ています。偉大な心は似ていると思いますか? :)

    関連する問題