Существует ли способ использовать переменную в качестве модификатора в замене?
my $search = 'looking';
my $replace = '"find: $1 ="';
my $modifier = 'ee';
s/$search/$replace/$modifier;
Я должен использовать массив хешей для создания объемной поисковой замены различными модификаторами.
Хм, если бы мне пришлось это сделать, я бы сделал так:
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})
, документированные в том же разделе perlre. Для всех форм eval
e
или ee
подумайте о безопасности получаемого кода!
Насколько я знаю, нет формы для изменения глобального на первое совпадение, поэтому глобальное и первое совпадение должны быть отдельными утверждениями.
Вот комбинация ответа Kinopiko и 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;
Чтобы быть полностью полезным, необходимо: