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

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

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

s/$search/$replace/$modifier;

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

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

Вы могли бы использовать 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";

Хотя метод с использованием 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

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

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

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

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

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

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" будут идти к одной и той же клавише.
Другие вопросы по тегам