ChatGPT解决这个技术问题 Extra ChatGPT

How do I perform a Perl substitution on a string while keeping the original?

In Perl, what is a good way to perform a replacement on a string using a regular expression and store the value in a different variable, without changing the original?

I usually just copy the string to a new variable then bind it to the s/// regex that does the replacement on the new string, but I was wondering if there is a better way to do this?

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

T
Timur Shtatland

This is the idiom I've always used to get a modified copy of a string without changing the original:

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

In perl 5.14.0 or later, you can use the new /r non-destructive substitution modifier:

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

NOTE:
The above solutions work without g too. They also work with any other modifiers.

SEE ALSO:
perldoc perlrequick: Perl regular expressions quick start


Whether or not under use strict. Minimal scoping of variables++
I was wondering if something like my $new = $_ for $old =~ s/foo/bar; would work?
@Benoit, I believe you mean s/foo/bar/ for my $newstring = $oldstring; It works, but it's far weirder.
L
Loovjo

The statement:

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

Which is equivalent to:

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

Alternatively, as of Perl 5.13.2 you can use /r to do a non destructive substitution:

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

Did you forget the g in your top regex?
t
the Tin Man

Under use strict, say:

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

instead.


b
brian d foy

The one-liner solution is more useful as a shibboleth than good code; good Perl coders will know it and understand it, but it's much less transparent and readable than the two-line copy-and-modify couplet you're starting with.

In other words, a good way to do this is the way you're already doing it. Unnecessary concision at the cost of readability isn't a win.


Ah, but the one line version isn't subject to the error in the question of unintentionally modifying the wrong string.
The one line version, if correctly executed, isn't subject, true. But that's a separate issue.
You might think it's unnecessary concision, but having to type a variable name twice to use it once is twice the number of points of failure. It's perfectly readable to people who know the language, and it's even in our Learning Perl course.
t
textral

Another pre-5.14 solution: http://www.perlmonks.org/?node_id=346719 (see japhy's post)

As his approach uses map, it also works well for arrays, but requires cascading map to produce a temporary array (otherwise the original would be modified):

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

t
the Tin Man

If you write Perl with use strict;, then you'll find that the one line syntax isn't valid, even when declared.

With:

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

You get:

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

Instead, the syntax that you have been using, while a line longer, is the syntactically correct way to do it with use strict;. For me, using use strict; is just a habit now. I do it automatically. Everyone should.

#!/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";

If you use warnings; instead of -w, you gain greater control: for instance, if you want to temporarily turn off warnings in a block of code.
V
Vrata Blazek

I hate foo and bar .. who dreamed up these non descriptive terms in programming anyway?

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

How is this different from the original? (And I think you want =~ s.)
Clbuttic mistake. The actual output of that code is newword donotnewword newword donotnewword newword donotnewword
See... if JoGotta had used the traditional and familiar foo and bar, his answer would have been accurate. Proving, once again, customs exist for a reason and lessons are only learned the hard way. ;)
Who? Wikipedia has part of the answer. Incl.: "The etymology of foobar could be derived from the military slang from the World War II era FUBAR, which was bowdlerised to foobar. The word foo on its own was used earlier. ... The first known use of the terms in print in a programming context appears in a 1965 edition of MIT's Tech Engineering News."
n
ngn999

if I just use this in oneliner, how about, sprintf("%s", $oldstring)