Как использовать переменную в качестве модификатора в подстановке - PullRequest
5 голосов
/ 13 июля 2010

Есть ли способ использовать переменную в качестве модификатора в подстановке?

my $search = 'looking';
my $replace = '"find: $1 ="';
my $modifier = 'ee';

s/$search/$replace/$modifier;

Мне нужно использовать массив хэшей, чтобы выполнить массовый поиск-замену различными модификаторами.

Ответы [ 5 ]

4 голосов
/ 13 июля 2010

Хотя метод, использующий eval для компиляции новой замены, является, вероятно, наиболее простым, вы можете создать замену, которая является более модульной:

use warnings;
use strict;

sub subst {
    my ($search, $replace, $mod) = @_;

    if (my $eval = $mod =~ s/e//g) {
        $replace = qq{'$replace'};
        $replace = "eval($replace)" for 1 .. $eval;
    } else {
        $replace = qq{"$replace"};
    }
    sub {s/(?$mod)$search/$replace/ee}
}

my $sub = subst '(abc)', 'uc $1', 'ise';

local $_ = "my Abc string";

$sub->();

print "$_\n";  # prints "my ABC string"

Это только слегка проверено, и читателю оставлено в качестве упражнения реализовать другие флаги, такие как g

4 голосов
/ 13 июля 2010

Вы можете использовать eval, если вы наденете защитные очки и свой костюм с делением на ноль.

например:.

use strict;
use warnings;
sub mk_re {
  my ($search, $replace, $modifier) = @_;
  $modifier ||= '';
  die "Bad modifier $modifier" unless $modifier =~ /^[msixge]*$/;
  my $sub = eval "sub { s/($search)/$replace/$modifier; }";
  die "Error making regex for [$search][$replace][$modifier]: $@" unless $sub;
  return $sub;
}

my $search = 'looking';
my $replace = '"find: $1 ="';
my $modifier = 'e';

# Sub can be stored in an array or hash
my $sub = mk_re($search, $replace, $modifier);

$_ = "abc-looking-def";
print "$_\n";
$sub->();
print "$_\n";
3 голосов
/ 13 июля 2010

Хм, если бы мне пришлось это сделать, я бы сделал так:

use warnings;
use strict;
my @stuff = (
{
    search => "this",
    replace => "that",
    modifier => "g",
},
{
    search => "ono",
    replace => "wendy",
    modifier => "i",
}
);
$_ = "this ono boo this\n";
for my $h (@stuff) {
    if ($h->{modifier} eq 'g') {
        s/$h->{search}/$h->{replace}/g;
    } elsif ($h->{modifier} eq 'i') {
        s/$h->{search}/$h->{replace}/i;
    }
    # etc.
}
print;

Существует только так много разных модификаторов, которые вы можете использовать, поэтому я думаю, что это достаточно просто.

Вы можете использовать eval для этого, но это ужасно грязно.

2 голосов
/ 14 июля 2010

Вот комбинация ответа Кинопико и его оценки.

eval используется здесь для генерации таблицы поиска контролируемым и поддерживаемым образом, а таблица поиска используется для сохранения всех if .. elsif.. эльсиф, на который не так весело смотретьвозможные модификаторы

функция сортировки в таблице поиска, поэтому комбинация «msi» и комбинация «mis» будут идти к одной и той же клавише.
2 голосов
/ 13 июля 2010

Конечно s/$search/$replace/ работает, как вы ожидаете. Это динамические модификаторы, которые не являются прямыми.

Для обычных совпадений модификаторы из pimsx вы можете использовать Perl's Extended Patterns для изменения флагов модификаторов на лету как части вашего шаблона. Они имеют форму (?pimsx-imsx) для включения / выключения этих модификаторов.

Для форм s// e и ee вы можете использовать (?{ perl code}), документированный в том же разделе perlre. Для всех форм eval e или ee учитывайте безопасность полученного кода!

Не существует формы для изменения глобального соответствия первому совпадению, о котором я знаю, поэтому глобальное сопоставление с первым соответствием должно быть отдельным оператором.

...