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

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

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

s/$search/$replace/$modifier;

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


person bem33    schedule 13.07.2010    source источник
comment
Некоторые модификаторы могут быть предоставлены внутри регулярного выражения как (?modifier:pattern), но не вещи, которые влияют на все, например / g или / e. Это одна из тех причин, почему вы делаете такие моменты. Если бы вы сказали нам, для чего это нужно, мы могли бы придумать более простой способ вместо того, чтобы прикасаться к верблюжьей шерсти (и открывать дыру в безопасности).   -  person Schwern    schedule 13.07.2010
comment
@Schwern: А самое неприятное, если дырку в верблюде проделать   -  person Borodin    schedule 12.06.2015


Ответы (5)


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

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 для этого, но это ужасно беспорядочно.

person Community    schedule 13.07.2010
comment
Беспорядок в глазах смотрящего. Я считаю это более беспорядочным, чем решение eval. - person runrig; 13.07.2010
comment
@runrig: беспорядок в этом случае не относится к тому, как выглядит код. Если вы используете eval, вам нужно позаботиться о множестве сложных для отслеживания ошибок. - person ; 14.07.2010
comment
Это решение, о котором я думал, прежде чем спросить Stackoverflox. - person bem33; 14.07.2010
comment
Что беспорядка в этом решении, так это дублированный код, который очень сложно поддерживать, если есть 6 модификаторов, это означает, что существует 63 возможных комбинации (без учета порядка). если вы измените что-то в одном if, вам нужно будет изменить это во всех, что ужасно для сопровождения кода. Я думаю, что лучше всего генерировать возможности динамически с помощью управляемого eval (), один из возможных способов - это ответ, который я опубликовал. - person miedwar; 14.07.2010
comment
С eval вам не нужно компилировать регулярное выражение при каждом использовании. Если эти замены выполняются более одного раза в одном сеансе, я бы, вероятно, выбрал eval. - person runrig; 14.07.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

person Eric Strom    schedule 13.07.2010
comment
Почему при каждой замене присутствует модификатор «ee»? - person runrig; 14.07.2010
comment
@runrig = ›казалось необходимым для правильной работы встроенных вычислений без исключения фактической замены. Может быть, есть способ получше, я не тратил время на его оптимизацию. - person Eric Strom; 15.07.2010

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

E.g.:

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";
person mob    schedule 13.07.2010
comment
В моем костюме деления на ноль есть дыра около минус бесконечности - person Borodin; 12.06.2015

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

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

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

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

person dawg    schedule 13.07.2010

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

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

(очень легко протестировано)

my @stuff = (
{
    search => "this",
    replace => "that",
    modifier => "g",
},
{
    search => "ono",
    replace => "wendy",
    modifier => "i",
}
);
$_ = "this ono boo this\n";

my @modifiers = qw{m s i x g e};

my $s_lookup = {};

foreach my $modifier (@modifiers) { 
    $s_lookup->{$modifier} =  eval " sub { s/\$_[0]/\$_[1]/$modifier } ";
}

for my $h (@stuff) {
    $s_lookup->{$h->{modifier}}->($h->{search},$h->{replace});
}

print; 

Чтобы быть полностью полезным, необходимо:

  1. комбинации возможных модификаторов
  2. функция сортировки в поисковой таблице, чтобы комбинация «msi» и «mis» попадала на один и тот же ключ.
person miedwar    schedule 13.07.2010
comment
Или просто добавьте проверку валидации модификатора к другому ответу eval, например, к тому, что есть сейчас. - person runrig; 14.07.2010