Встроенная замена регулярных выражений в Perl - PullRequest
10 голосов
/ 26 июля 2010

Есть ли способ заменить текст встроенным регулярным выражением вместо того, чтобы брать текст из переменной и сохранять его в переменной?

Я новичок в Perl.Я часто пишу

my $foo = $bar;
$foo =~ s/regex/replacement/;
doStuff($foo)

, где я действительно хотел бы написать

doStuff($bar->replace(s/regex/replacement/));

или подобное, вместо того, чтобы использовать временную переменную и три строки.

Есть ли способ сделать это?Очевидно, что когда регулярное выражение является достаточно сложным, имеет смысл разделить его, чтобы его можно было лучше объяснить, но когда это просто s/\s//g, то кажется неправильным загромождать код дополнительными переменными.

Ответы [ 6 ]

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

Вы действительно не можете делать то, что хотите, потому что функция подстановки возвращает либо 1, если она сработала, либо пустую строку, если она не сработала.Это означает, что если вы сделали это:

doStuff($foo =~ s/regex/replacement/);

Функция doStuff будет использовать либо 1, либо пустую строку в качестве параметра.Нет причины, по которой функция подстановки не смогла бы вернуть результирующую строку вместо 1, если она работала.Тем не менее, это было дизайнерское решение с самых ранних дней Perl.Иначе, что случилось бы с этим?

$foo = "widget";
if ($foo =~ s/red/blue/) {
    print "We only sell blue stuff and not red stuff!\n";
}

Результирующая строка по-прежнему widget, но замена фактически не удалась.Однако, если подстановка вернула результирующую строку, а не пустую строку, if все равно будет истинным.

Затем рассмотрим следующий случай:

$bar = "FOO!";
if ($bar =~ s/FOO!//) {
   print "Fixed up \'\$bar\'!\n";
}

$bar сейчаспустая строка.Если подстановка вернет результат, она вернет пустую строку.Тем не менее, подстановка действительно прошла успешно, и я хочу, чтобы мой if был истинным.

В большинстве языков функция подстановки возвращает результирующую строку, и вам придется сделать что-то вроде этого:

if ($bar != replace("$bar", "/FOO!//")) {
   print "Fixed up \'\$bar''!\n";
}

Таким образом, из-за решения по дизайну Perl (в основном для лучшего имитации синтаксиса awk), нет простого способа сделать то, что вы хотите.Однако вы могли бы сделать это:

($foo = $bar) =~ s/regex/replacement/;
doStuff($foo);

Это установило бы на месте значение $foo без предварительного присвоения ему значения $bar.$bar останется без изменений.

5 голосов
/ 10 августа 2016

Начиная с Perl 5.14, вы можете использовать Неразрушающее замещение для достижения желаемого поведения.

Для этого используйте модификатор /r:

doStuff($bar=~s/regex/replacement/r);
5 голосов
/ 26 июля 2010
use Algorithm::Loops "Filter";

# leaves $foo unchanged
doStuff( Filter { s/this/that/ } $foo );
2 голосов
/ 26 июля 2010

Вы можете использовать блок do { }, чтобы избежать создания временной переменной в текущей области:

doStuff( do {(my $foo = $bar) =~ s/regex/replacement/; $foo} );
0 голосов
/ 26 июля 2010

Есть еще один способ: написать свою собственную функцию:

sub replace (
    my $variable = shift;
    my $substring = shift;

    eval "\$variable =~ s${substring};";
    return $variable
}

doStuff(replace($foo, "/regex/replace/"));

Это не будет стоить одного звонка, и, вероятно, в этом случае ваш код будет более запутанным. Однако, если вы делаете это около десятка раз, возможно, имеет смысл написать собственную функцию для этого.

0 голосов
/ 26 июля 2010

Это то, что вы хотите?:

my $foo = 'Replace this with that';
(my $bar = $foo) =~ s/this/that/;
print "Foo: $foo\nBar: $bar\n";

Отпечатки:

Foo: Replace this with that
Bar: Replace that with that
...