Como executo uma substituição Perl em uma string, mantendo o original?

180

No Perl, qual é uma boa maneira de executar uma substituição em uma string usando uma expressão regular e armazenar o valor em uma variável diferente, sem alterar o original?

Normalmente, apenas copio a string para uma nova variável e a s///vinculo ao regex que substitui a nova string, mas queria saber se existe uma maneira melhor de fazer isso?

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

Respostas:

257

Este é o idioma que eu sempre usei para obter uma cópia modificada de uma string sem alterar o original:

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

No perl 5.14.0 ou posterior, você pode usar o novo /r modificador de substituição não destrutivo :

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

Nota: As soluções acima gtambém funcionam sem . Eles também trabalham com outros modificadores.

John Siracusa
fonte
6
Seja ou não em uso estrito.
Escopo
Eu queria saber se algo como my $new = $_ for $old =~ s/foo/bar;iria funcionar?
Benoit
2
@Benoit, acredito que você quer dizer que s/foo/bar/ for my $newstring = $oldstring;funciona, mas é muito mais estranho.
Ikegami
43

A declaração:

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

O que equivale a:

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

Como alternativa, a partir do Perl 5.13.2, você pode usar /rpara fazer uma substituição não destrutiva:

use 5.013;
#...
my $newstring = $oldstring =~ s/foo/bar/gr;
Pat
fonte
3
Você esqueceu o gno seu regex superior?
mareoraft
23

Abaixo use strict, diga:

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

em vez de.

Sam Kington
fonte
10

A solução de uma linha é mais útil como shibboleth do que como um bom código; bons codificadores Perl o conhecerão e entenderão, mas é muito menos transparente e legível do que o dístico de duas linhas para copiar e modificar com o qual você está começando.

Em outras palavras, uma boa maneira de fazer isso é como você está fazendo. Concisão desnecessária ao custo da legibilidade não é uma vitória.

Josh Millard
fonte
Ah, mas a versão de uma linha não está sujeita ao erro na questão de modificar involuntariamente a string errada.
ysth 19/09/08
A versão de uma linha, <i> se executada corretamente </i>, não é assunto, é verdade. Mas isso é uma questão separada.
Josh Millard
9
Você pode pensar que é uma concisão desnecessária, mas ter que digitar um nome de variável duas vezes para usá-lo uma vez é o dobro do número de pontos de falha. É perfeitamente legível para as pessoas que conhecem o idioma e está presente no curso <i> Learning Perl </i>.
22138 brian d foy
1

Outra solução anterior à 5.14: http://www.perlmonks.org/?node_id=346719 (consulte a publicação do japhy)

Como sua abordagem usa map, também funciona bem para matrizes, mas requer cascata mappara produzir uma matriz temporária (caso contrário, o original seria modificado):

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

Eu odeio foo e bar .. quem inventou esses termos não descritivos em programação?

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
JoGotta
fonte
2
Como isso é diferente do original? (E eu acho que você quer =~ s.)
Teepeemm
Erro cluttico. A saída real desse código é #newword donotnewword newword donotnewword newword donotnewword
Pascal
2
Veja ... se JoGotta tivesse usado o tradicional e o familiar fooe bar, sua resposta teria sido precisa. Provando, mais uma vez, os costumes existem por uma razão e as lições são aprendidas apenas da maneira mais difícil. ;)
Jon
-1

Se você escrever Perl use strict;, verá que a sintaxe de uma linha não é válida, mesmo quando declarada.

Com:

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

Você obtém:

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

Em vez disso, a sintaxe que você está usando, enquanto uma linha mais longa, é a maneira sintaticamente correta de fazer isso use strict;. Para mim, usar agora use strict;é apenas um hábito. Eu faço isso automaticamente. Todo mundo deveria.

#!/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";
Tim Kennedy
fonte
1
Se você em use warnings;vez de -w, obtém maior controle: por exemplo, se deseja desativar temporariamente os avisos em um bloco de código.
21139 Glenn Jackman