Perl qr // и подстановка - PullRequest
       12

Perl qr // и подстановка

6 голосов
/ 03 августа 2009

Я пишу крошечную программу, которая принимает пользовательский ввод с помощью Getops, и на его основе программа либо попытается сопоставить шаблон с каким-либо текстом, либо заменить текст на соответствующий.

У меня проблема в том, что я не могу заставить замещающую часть работать. Я смотрю на запись qr // на страницах man: http://perldoc.perl.org/perlop.html#Regexp-Quote-Like-Operators, но мне не повезло с этим. Я попытался смоделировать мой код точно так же, как документы в этом случае. Я компилирую шаблон соответствия и подставляю его в подстановку.

Может ли кто-нибудь указать, где я иду не так? (Не беспокойтесь о безопасности, это всего лишь небольшой скрипт для личного использования)

Вот что я смотрю:

if($options{r}){

    my $pattern = $options{r};
    print "\nEnter Replacement text: ";
    my $rep_text = <STDIN>;

    #variable grab, add flags to pattern if they exist.
    $pattern .= 'g' if $options{g};
    $pattern .= 'i' if $options{i};
    $pattern .= 's' if $options{s};


    #compile that stuff
    my $compd_pattern = qr"$pattern" or die $@;
    print $compd_pattern; #debugging

    print "Please enter the text you wish to run the pattern on: ";
    my $text = <STDIN>;
    chomp $text;    

    #do work and display
    if($text =~ s/$compd_pattern/$rep_text/){ #if the text matched or whatever
        print $text;
    }
    else{
        print "$compd_pattern on \n\t{$text} Failed. ";
    }
} #end R FLAG

Когда я запускаю его с -r "/ matt /" -i и ввожу заменяющий текст 'matthew', в текст 'matt' произойдет сбой. Почему это?

РЕДАКТИРОВАТЬ:

Спасибо за ответы, ребята! Это было действительно очень полезно. Я объединил оба ваших предложения в рабочее решение проблемы. Я должен обрабатывать флаг / g немного по-другому. Вот рабочий образец:

if($options{r}){

    my $pattern = $options{r};
    print "\nEnter Replacement text: ";
    my $rep_text = <STDIN>;
    chomp $rep_text;

    #variable grab, add flags to pattern if they exist.

    my $pattern_flags .= 'i' if $options{i};
    $pattern_flags .= 's' if $options{s};

    print "Please enter the text you wish to run the pattern on: ";
    my $text = <STDIN>;
    chomp $text;    

    #do work and display
    if($options{g}){
        if($text =~ s/(?$pattern_flags:$pattern)/$rep_text/g){ #if the text matched or whatever (with the g flag)
            print $text;
        }
        else{
            print "$pattern on \n\t{$text} Failed. ";
        }
    }
    else{
        if($text =~ s/(?$pattern_flags:$pattern)/$rep_text/){ #if the text matched or whatever
            print $text;
        }
        else{
            print "$pattern on \n\t{$text} Failed. ";
        }
    }
} #end R FLAG

Ответы [ 2 ]

11 голосов
/ 03 августа 2009

Как указывает хаос, вы столкнетесь с некоторыми трудностями при использовании qr//. Вам действительно нужно предварительно скомпилировать шаблон? Если нет, то такая стратегия может сработать:

my $pattern      = 'matt';
my $text         = 'Matt';
my $rep_text     = 'Matthew';
my $pattern_opts = 'i';

print $text, "\n" if $text =~ s/(?$pattern_opts:$pattern)/$rep_text/;

Обновление в ответ на ваш новый код : вы можете рассмотреть возможность использования такого подхода:

my ($orig, $patt, $rep, $flags) = qw(FooFooFoo foo bar ig);

my $make_replacement = $flags =~ s/g//        ?
    sub { $_[0] =~ s/(?$flags:$patt)/$rep/g } :
    sub { $_[0] =~ s/(?$flags:$patt)/$rep/  }
;

if ( $make_replacement->($orig) ){
    print $orig;
}
else {
    print "Failed...";
}
7 голосов
/ 03 августа 2009

Запустите его с -r "matt", а не -r "/matt/". Вам не нужно и фактически невозможно указывать разделители шаблонов в строке параметров. Кавычки - это разделители в вашем qr. Так что на самом деле он ищет matt с косыми чертами вокруг него, то, как вы его используете, а это не то, что вам нужно. Вы пытаетесь использовать кавычки, чтобы сказать Perl, что нужно обрабатывать строку шаблона, как если бы это был исходный код, но, к сожалению, вы не можете этого сделать.

Все те паттерны, которые вы делаете для других опций, также не будут работать. Вам нужно будет изменить способ компиляции регулярного выражения, если вы хотите сделать все это. Нечто подобное может сделать это для /i и /s:

my $compd_pattern = qr/$pattern/ or die $@;
$compd_pattern = qr/$compd_pattern/i if $options{i};
$compd_pattern = qr/$compd_pattern/s if $options{s};

Для /g вам потребуется поддержка альтернативной версии поиска / замены. /g не является допустимым модификатором qr//.

...