Want to win a PS4? Go Premium and enter to win our High-Tech Treats giveaway. Enter to Win

x
?
Solved

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

Posted on 2012-04-09
11
Medium Priority
?
426 Views
Last Modified: 2012-04-09
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!
0
Comment
Question by:JonHodgson
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 6
  • 4
11 Comments
 
LVL 31

Expert Comment

by:farzanj
ID: 37824436
Change
my $replace='$1---';
to
my $replace="$1---";
0
 

Author Comment

by:JonHodgson
ID: 37824642
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
 
LVL 31

Expert Comment

by:farzanj
ID: 37824701
Need your input file(s).
0
Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

 

Author Comment

by:JonHodgson
ID: 37824716
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
 

Author Comment

by:JonHodgson
ID: 37824995
Here's the file in case that's easier for you.
subtest.cfg.txt
0
 
LVL 31

Accepted Solution

by:
farzanj earned 2000 total points
ID: 37825250
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
 

Author Comment

by:JonHodgson
ID: 37825387
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
 
LVL 84

Expert Comment

by:ozo
ID: 37825428
$replace='"$1---"';      
 $string =~ s/$search/$replace/ee ;
0
 

Author Comment

by:JonHodgson
ID: 37825469
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
 
LVL 31

Assisted Solution

by:farzanj
farzanj earned 2000 total points
ID: 37825525
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
 

Author Closing Comment

by:JonHodgson
ID: 37825581
Farzanj,

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

- Jon
0

Featured Post

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

I've just discovered very important differences between Windows an Unix formats in Perl,at least 5.xx.. MOST IMPORTANT: Use Unix file format while saving Your script. otherwise it will have ^M s or smth likely weird in the EOL, Then DO NOT use m…
On Microsoft Windows, if  when you click or type the name of a .pl file, you get an error "is not recognized as an internal or external command, operable program or batch file", then this means you do not have the .pl file extension associated with …
Explain concepts important to validation of email addresses with regular expressions. Applies to most languages/tools that uses regular expressions. Consider email address RFCs: Look at HTML5 form input element (with type=email) regex pattern: T…
Six Sigma Control Plans

618 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question