Link to home
Start Free TrialLog in
Avatar of JonHodgson
JonHodgsonFlag for United States of America

asked on

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!
Avatar of farzanj
farzanj
Flag of Canada image

Change
my $replace='$1---';
to
my $replace="$1---";
Avatar of JonHodgson

ASKER

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.
Need your input file(s).
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)
Here's the file in case that's easier for you.
subtest.cfg.txt
ASKER CERTIFIED SOLUTION
Avatar of farzanj
farzanj
Flag of Canada image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
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
$replace='"$1---"';      
 $string =~ s/$search/$replace/ee ;
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
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Farzanj,

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

- Jon