Как выполнить замену Perl в строке при сохранении оригинала?

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

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

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

7 ответов


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

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

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

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

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


инструкции:

(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;

под use strict, говорят:

(my $new = $original) =~ s/foo/bar/;

вместо.


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

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


Я ненавижу 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

другое pre-5.14 решение:http://www.perlmonks.org/?node_id=346719 (см. сообщение джафи)

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

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

если вы пишете 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";