Как выполнить инструкцию AWK в скрипте Perl, который использует переменную Perl - PullRequest
1 голос
/ 24 января 2012

Я пытаюсь использовать оператор awk внутри perl-скрипта, который принимает пользовательский ввод и выполняет поиск по нескольким текстовым файлам, чтобы найти строки, которые соответствуют всем словам в вводе в любом порядке. С этой целью я могу выполнить поиск Awk, который я хочу, по CLI следующим образом:

awk 'tolower($0) ~ / 204/ && / test/ && / leg/' *_Codes.txt

При этом будут возвращены строки в ссылочных текстовых файлах, которые включают слова, начинающиеся с «204», «тест» и «нога», например, «левые ноги проверяются в комнате 2045»;

Однако, когда я пытаюсь сделать это в скрипте Perl, устанавливая пользовательский ввод в переменную и изменяя его, чтобы включить операторы и слэши &&, я ничего не получаю обратно. Вот что у меня есть:

my ($code_search, $code_set) = @_;

# Clean the input for awk
# trim whitespace from the ends
$code_search =~ s!(^\s+|\s+$)!!g;

# separate words with the && operator and slashes
$code_search =~ s!\s+!/ && / !g;

# make input lower case and tack on front and back slashes 
my $sanitized_query = lc "/ ${code_search}/";

# at this point, a user input of '204 leg test'
# is transformed to '/ 204/ && / leg/ && / test/'
# and is saved to the $sanitized_query variable

# run the query through awk and save it to $results
my $results = `awk 'tolower($0) ~ \$sanitized_query' *_Codes.txt`;

Но $results ничего мне не дает.

Возможно, awk не является подходящим инструментом для этой работы, но он лучше подходит для моих нужд, чем grep, так как я хочу убедиться, что могу найти все введенные термины и вернуть результаты там, где они все появляются в строка текста в любом порядке.

Любая помощь очень ценится.

Ответы [ 5 ]

6 голосов
/ 24 января 2012

Почему бы не сделать это полностью на Perl, а не с помощью awk?Вы должны быть в состоянии открыть файл, прочитать в каждой строке и распечатать его, если регулярное выражение совпадает.Регулярные выражения - одна из сильных сторон Perls, почему бы не использовать их напрямую, а не пытаться вызывать awk?

Единственное преимущество, которое я вижу при использовании awk, заключается в том, что вам придется вручную перечислять все * _CodesTXT-файлы, но это не должно быть слишком сложно в Perl.

Самый простой способ сделать это в Perl, если у вас есть строка текста, это просто запустить регулярное выражение 3 раза, по одному для каждогочасть, которую вы пытаетесь сопоставить.Например, если вы хотите сопоставить 204, test и leg, вы можете выполнить

if (($line =~ m/ 204/i) && ($line =~ m/ test/i) && ($line =~ m/ leg/i)){
    print $line;
}
3 голосов
/ 24 января 2012

$0 также является допустимым символом в Perl (он содержит имя текущего запущенного сценария Perl) и также интерполируется внутри обратных кавычек. Тебе тоже нужно сбежать:

my $results = `awk 'tolower(\$0) ~ \$sanitized_query' *_Codes.txt`;
2 голосов
/ 24 января 2012

Чтобы развить то, что сказал @mob, я думаю, что это выход из проблемы. Хотя он слишком много избегает. Вам нужно что-то вроде этого:

my $results = `awk 'tolower(\$0) ~ $sanitized_query' *_Codes.txt`;

Вы хотите, чтобы $0 было буквальным, а $sanitized_query - интерполированным. (В приведенном выше примере кода вы избегаете неправильного).

2 голосов
/ 24 января 2012

Решение Pure Perl, включая разбиение $code_search, глобализацию имен файлов и сопоставление шаблонов только в начале слов:

use List::MoreUtils qw{ all };

my @words = ($code_search =~ m/\S+/g);

for my $fn (glob('*_Codes.txt')) {
    open my $f, '<', $fn || die "Can't open: $!";

    while (defined(my $line = <$f>)) {
        if (all { $line =~ m{\b\Q$_\E}is } @words) { print $line }
    }

    close $f;
}

Если вы не хотите зависеть от List :: MoreUtils, затем измените 'if' на:

        if (!grep { $line !~ m{\b\Q$_\E}is } @words) { print $line }

- немного сложнее для чтения, но использует только встроенные perl.

1 голос
/ 24 января 2012

Хотя ответ Сколора полностью уместен, здесь используется несколько иной подход, использующий оператор интеллектуального сопоставления (который доступен в Perl версии 5.10 или выше).Если строки вашего текстового файла действительно длинные и если у вас не так много слов для сравнения со строками, это может быть более быстрый подход (акцент на «сила»).

use strict;
use warnings;

my @query_words=qw(204 test leg);

open(my $read,"<","input_file") or die $!;

while(<$read>)
{
  chomp; #get rid of trailing newline
  my @words=split(/\s+/,$_); #split on spaces to get actual words

  foreach my $q (@query_words)
  {
    if($q~~@words) #If we have a match, print and exit the loop.
    {
      print "$_\n";
      last;
    }
  }
}

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