Как я могу раскрыть переменные в строке Perl? - PullRequest
0 голосов
/ 25 февраля 2009

Я пытаюсь развернуть строку $searchCriteria в условии if. Любые подсказки?

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 $_;
    }
}

Ответы [ 6 ]

3 голосов
/ 25 февраля 2009

Если ваши критерии поиска являются регулярными выражениями, вы должны подготовить свое собственное скомпилированное регулярное выражение. Также обратите внимание на использование цикла 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);
};
1 голос
/ 25 февраля 2009

Похоже, вы хотите оценить, содержит ли строка ВСЕ аргументы в @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 - $@" if $@;
    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 голос
/ 25 февраля 2009

Хм ... Я не уверен, в чем вопрос ... но почему-то я подозреваю, что вам нужно выражение qr // (цитируемое регулярное выражение).

0 голосов
/ 26 февраля 2009

Посмотрев на Взяв ответ Хайнка-Пичи-Выходила Я понял, что вы можете значительно упростить всю эту задачу с помощью функции List :: MoreUtil's 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;

Подставить all с any для совпадения на основе "или".

Редактировать: Черт, похоже, что Аксеман опубликовал нечто очень похожее на это. Великие умы думают одинаково, а? :)

0 голосов
/ 26 февраля 2009

Вы можете создать одно регулярное выражение, которое будет работать, ЕСЛИ аргументы не являются выражениями регулярного выражения.

Идея заключается в следующей последовательности:

  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 голосов
/ 25 февраля 2009

Какой у тебя вопрос? Возможно, вы ищете 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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...