Come eseguo una sostituzione Perl su una stringa mantenendo l'originale?


180

In Perl, qual è un buon modo per eseguire una sostituzione su una stringa usando un'espressione regolare e memorizzare il valore in una variabile diversa, senza cambiare l'originale?

Di solito copio solo la stringa in una nuova variabile e poi la s///associo alla regex che fa la sostituzione sulla nuova stringa, ma mi chiedevo se c'è un modo migliore per farlo?

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

Risposte:


257

Questo è il linguaggio che ho sempre usato per ottenere una copia modificata di una stringa senza cambiare l'originale:

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

In perl 5.14.0 o successivo, è possibile utilizzare il nuovo /r modificatore di sostituzione non distruttiva :

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

Nota: le soluzioni precedenti funzionano ganche senza . Funzionano anche con qualsiasi altro modificatore.


6
Indipendentemente dal fatto che sia in uso rigoroso.
Scoping

Mi chiedevo se qualcosa del genere my $new = $_ for $old =~ s/foo/bar;avrebbe funzionato?
Benoit,

2
@Benoit, credo che intendi che s/foo/bar/ for my $newstring = $oldstring;funziona, ma è molto più strano.
ikegami,

43

La dichiarazione:

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

Che equivale a:

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

In alternativa, a partire da Perl 5.13.2 è possibile utilizzare /rper effettuare una sostituzione non distruttiva:

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

3
Hai dimenticato il gnella tua regex top?
mareoraft,

23

Sotto use strict, dire:

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

anziché.


10

La soluzione one-liner è più utile come shibboleth che un buon codice; i bravi programmatori Perl lo sapranno e lo capiranno, ma è molto meno trasparente e leggibile del couplet di due righe copia-e-modifica con cui stai iniziando.

In altre parole, un buon modo per farlo è il modo in cui lo stai già facendo. Una concisione non necessaria a scapito della leggibilità non è una vittoria.


Ah, ma la versione a una riga non è soggetta all'errore nella questione della modifica involontaria della stringa errata.
ysth

La versione a una riga, <i> se eseguita correttamente </i>, non è soggetto, vero. Ma questo è un problema separato.
Josh Millard,

9
Potresti pensare che sia una concisione non necessaria, ma dover digitare un nome di variabile due volte per usarlo una volta è il doppio del numero di punti di errore. È perfettamente leggibile per le persone che conoscono la lingua ed è persino presente nel nostro corso <i> Learning Perl </i>.
brian d foy,

1

Un'altra soluzione pre-5.14: http://www.perlmonks.org/?node_id=346719 (vedi il post di japhy)

Come usa il suo approccio map, funziona bene anche per le matrici, ma richiede la cascata mapper produrre una matrice temporanea (altrimenti l'originale verrebbe modificato):

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

1

Odio foo e bar .. chi ha comunque immaginato questi termini non descrittivi nella programmazione?

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
In che cosa differisce dall'originale? (E penso che tu voglia =~ s.)
Teepeemm,

Errore cluttico. L'output effettivo di quel codice ènewword donotnewword newword donotnewword newword donotnewword
Pascal,

2
Vedi ... se JoGotta avesse usato il tradizionale e il familiare fooe bar, la sua risposta sarebbe stata accurata. Provare, ancora una volta, che esistono costumi per una ragione e le lezioni vengono apprese solo nel modo più duro. ;)
Jon

-1

Se scrivi Perl con use strict;, allora scoprirai che la sintassi di una riga non è valida, anche se dichiarata.

Con:

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

Ottieni:

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

Invece, la sintassi che hai usato, mentre una linea più lunga, è il modo sintatticamente corretto per farlo use strict;. Per me, usare use strict;è solo un'abitudine ora. Lo faccio automaticamente. Tutti dovrebbero.

#!/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
Se use warnings;invece -w, ottieni un maggiore controllo: ad esempio, se desideri disattivare temporaneamente gli avvisi in un blocco di codice.
Glenn Jackman,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.