Как выполнить подстановку Perl для строки, сохранив оригинал?


180

В Perl, что является хорошим способом выполнить замену строки с помощью регулярного выражения и сохранить значение в другой переменной, не изменяя оригинал?

Я обычно просто копирую строку в новую переменную, а затем связываю ее с s///регулярным выражением, которое выполняет замену новой строки, но мне было интересно, есть ли лучший способ сделать это?

$newstring = $oldstring;
$newstring =~ s/foo/bar/g;

Ответы:


257

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

(my $newstring = $oldstring) =~ s/foo/bar/g;

В Perl 5.14.0 или новее вы можете использовать новый /r модификатор неразрушающего замещения :

my $newstring = $oldstring =~ s/foo/bar/gr; 

Примечание: вышеуказанные решения работают без gслишком. Они также работают с любыми другими модификаторами.


6
Будь или не под строгим использованием. Минимальная область видимости переменных ++
ysth

Мне было интересно, если что-то подобное my $new = $_ for $old =~ s/foo/bar;будет работать?
Бенуа

2
@ Бенуа, я думаю, ты имеешь в виду, что s/foo/bar/ for my $newstring = $oldstring;это работает, но это гораздо страннее.
Ikegami

43

Заявление:

(my $newstring = $oldstring) =~ s/foo/bar/g;

Что эквивалентно:

my $newstring = $oldstring;
$newstring =~ s/foo/bar/g;

В качестве альтернативы, с Perl 5.13.2 вы можете использовать /rдля неразрушающего замещения:

use 5.013;
#...
my $newstring = $oldstring =~ s/foo/bar/gr;

3
Вы забыли gв своем регулярном выражении?
'23


10

Однострочное решение более полезно, чем шибболет, чем хороший код; Хорошие Perl-кодеры будут знать и понимать его, но он гораздо менее прозрачен и читаем, чем двухстрочный куплет-копируй-и-изменяй, с которого ты начинаешь.

Другими словами, хороший способ сделать это - это то, что вы уже делаете. Ненужное сжатие за счет читабельности не является победой.


Ах, но однострочная версия не подвержена ошибке в вопросе непреднамеренного изменения неправильной строки.
ysth

Однострочная версия, <i> если правильно выполнено </ i>, не подчиняется, true. Но это отдельная проблема.
Джош Миллард

9
Вы можете подумать, что это излишняя краткость, но необходимость дважды вводить имя переменной, чтобы использовать его один раз, вдвое больше точек отказа. Он отлично читается людьми, знающими язык, и даже в нашем курсе <i> Learning Perl </ i>.
Брайан д Фой

1

Другое решение до 5.14: http://www.perlmonks.org/?node_id=346719 (см. Пост japhy)

Поскольку его подход использует map, он также хорошо работает для массивов, но требует каскадного mapсоздания временного массива (в противном случае оригинал будет изменен):

my @orig = ('this', 'this sucks', 'what is this?');
my @list = map { s/this/that/; $_ } map { $_ } @orig;
# @orig unmodified

1

Я ненавижу foo и bar .. кто придумал эти неописательные термины в программировании?

my $oldstring = "replace donotreplace replace donotreplace replace donotreplace";

my $newstring = $oldstring;
$newstring =~ s/replace/newword/g; # inplace replacement

print $newstring;
%: newword donotreplace newword donotreplace newword donotreplace

2
Чем это отличается от оригинала? (И я думаю, что вы хотите =~ s.)
Teepeemm

Грубая ошибка. Фактический вывод этого кодаnewword donotnewword newword donotnewword newword donotnewword
Паскаль

2
Смотрите ... если JoGotta использовал традиционные и знакомые , fooи barего ответ был бы точным. Доказательство, еще раз, обычаи существуют по причине, и уроки изучены только трудным путем. ;)
Джон

-1

Если вы напишите на Perl use strict;, то вы обнаружите, что однострочный синтаксис недействителен, даже если объявлен.

С участием:

my ($newstring = $oldstring) =~ s/foo/bar/;

Ты получаешь:

Can't declare scalar assignment in "my" at script.pl line 7, near ") =~"
Execution of script.pl aborted due to compilation errors.

Вместо этого, синтаксис, который вы использовали, хотя и длиннее строки, является синтаксически правильным способом сделать это use strict;. Для меня использование use strict;- это просто привычка. Я делаю это автоматически. Каждый должен.

#!/usr/bin/env perl -wT

use strict;

my $oldstring = "foo one foo two foo three";
my $newstring = $oldstring;
$newstring =~ s/foo/bar/g;

print "$oldstring","\n";
print "$newstring","\n";

1
Если вы use warnings;вместо этого -w, вы получаете больший контроль: например, если вы хотите временно отключить предупреждения в блоке кода.
Гленн Джекман
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.