PERL search-and-replace using variables [ s/$search/$replace/ ] and backreferences

I need to load a list of search-and-replace patterns (with backreferences) in from a config file and apply them to a series of strings. I can't figure out how to do a search-and-replace with backreferences using variables.

This is the RESULT i'm trying to achieve (shown first without using variables):
use strict;
my $string='foo1bar';
print "BEFORE: [$string]\n";
$string =~ s/(.*)\d/$1---/;
print "AFTER:  [$string]\n";

Open in new window

which works perfectly:
BEFORE: [foo1bar]
AFTER:  [foo---bar]


BUT, I need to achieve the same result using variables.
I tried the following:
use strict;
my $string='foo1bar';
my $search='(.*)\d';
my $replace='$1---';
print "BEFORE: [$string]\n";
$string =~ s/$search/$replace/;
print "AFTER:  [$string]\n";

Open in new window

But that did not work as I hoped:
BEFORE: [foo1bar]
AFTER:  [$1---bar]


I can't figure out how to get $1 to expand to the backreferenced value.
I tried playing with /e & /ee modifiers but those didn't work. Please help!
JonHodgsonAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

farzanjCommented:
Change
my $replace='$1---';
to
my $replace="$1---";
0
JonHodgsonAuthor Commented:
farazanj,

Thank you very much. You've gotten me closer to my ultimate solution. I didn't realize in this case there would be a difference between single & double quotes, as I assumed the variable substitution occurred at the time of assignment rather than at the time of evaluation.

I still need to achieve my ultimate goal of reading these patterns from a config file. It's behaving like my single-quote example and i'm not sure how to make it behave like your double-quote version:


use strict;
my %config;
open(CONFIG, "<subtest.cfg");
	# subtest.cfg contains: (whitespace is 2 tabs)
	# (.*)\d		$1---
	while(<CONFIG>){
		chomp;
		s/#.*//;	# No comments
		s/^\s+//;	# No leading whitespace
		s/\s+$//;	# No trailing whitespace
		next unless length;	# Skip blank lines
	
		my ($search,$replace) = split("\t\t",$_,2);
		$config{$search}=$replace;
	}
close(CONFIG);

my $string='foo1bar';
foreach my $search (keys %config) {
	my $replace=$config{$search};
	print "SEARCH: [$search]\n";
	print "REPLACE: [$replace]\n";
	print "BEFORE: [$string]\n";
	$string =~ s/$search/$replace/;
	print "AFTER:  [$string]\n\n";
}

Open in new window

It's outputting incorrectly:
SEARCH: [(.*)\d]
REPLACE: [$1---]
BEFORE: [foo1bar]
AFTER:  [$1---bar]


If I can get this to work this will solve my problem. Thanks.
0
farzanjCommented:
Need your input file(s).
0
Cloud Class® Course: Python 3 Fundamentals

This course will teach participants about installing and configuring Python, syntax, importing, statements, types, strings, booleans, files, lists, tuples, comprehensions, functions, and classes.

JonHodgsonAuthor Commented:
farzanj,

My code example showed the content of my input file in the comment where I opened the file:
# subtest.cfg contains: (whitespace is 2 tabs)
# (.*)\d            $1---

It's just:
(.*)\d<tab><tab>$1---

(That's the same search and replace as before, but with 2 tabs as the delimiter)
0
JonHodgsonAuthor Commented:
Here's the file in case that's easier for you.
subtest.cfg.txt
0
farzanjCommented:
Try this:
#!/usr/bin/perl

use strict;
my %config;
open(CONFIG, "<subtest.cfg");
    # subtest.cfg contains: (whitespace is 2 tabs)
    # (.*)\d        $1---
    while(<CONFIG>){
        chomp;
        s/#.*//;    # No comments
        s/^\s+//;   # No leading whitespace
        s/\s+$//;   # No trailing whitespace
        next unless length; # Skip blank lines

        my ($search,$replace) = split("\t\t",$_,2);
        $config{$search}=$replace;
    }
close(CONFIG);

my $string='foo1bar';
foreach my $search (keys %config) {
    my $replace= '"' . $config{$search}. '"';
    print "SEARCH: [$search]\n";
    print "REPLACE: [$replace]\n";
    print "BEFORE: [$string]\n";
    $string =~ s/$search/$replace/ee;
    print "AFTER:  [$string]\n\n";
}
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
JonHodgsonAuthor Commented:
farzanj,

That worked! Before I close this out and assign you all the points, can you please briefly explain WHY your changes worked?

This will help me and others not have this issue in the future.

Thanks,

Jon
0
ozoCommented:
$replace='"$1---"';      
 $string =~ s/$search/$replace/ee ;
0
JonHodgsonAuthor Commented:
Hi ozo/farzanj,

I wasn't asking which lines he made changes on. I already figured that out with diff.

I mean an EXPLANATION, in words, as to why that syntax was needed. I'm trying to LEARN why this worked rather than just cut-and-pasting the answer.

Thanks
0
farzanjCommented:
Ozo's solution would work if you always had the same replacement items but you want that to be a variable as well.

Some explanation:
s///ee;  e--evaluate.  Two 'e's  mean evaluate twice.
What you basically need for substitution is double quoted "$1---".  So I stored that in the string.  
Now what you should do is : remove one 'e' and see what you get.  This will help you understand what happens with a single evaluation.  Also look at string interpolation
http://perlmeme.org/howtos/using_perl/interpolation.html

And eval function
http://perldoc.perl.org/functions/eval.html

Here is another useful link
http://www.perlmonks.org/?node_id=687031
0
JonHodgsonAuthor Commented:
Farzanj,

Thanks so much for your solution and the explanation. I've awarded you all the points.

- Jon
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Perl

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.