Solved

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

Posted on 2012-04-09
11
393 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
  • 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
 

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
Highfive Gives IT Their Time Back

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 
LVL 31

Accepted Solution

by:
farzanj earned 500 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 500 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

Find Ransomware Secrets With All-Source Analysis

Ransomware has become a major concern for organizations; its prevalence has grown due to past successes achieved by threat actors. While each ransomware variant is different, we’ve seen some common tactics and trends used among the authors of the malware.

Join & Write a Comment

I have been reconstructing a PHP-based application that has grown into a full blown interface system over the last ten years by a developer that has now gone into business for himself building websites. I am not incredibly fond of writing PHP code o…
A year or so back I was asked to have a play with MongoDB; within half an hour I had downloaded (http://www.mongodb.org/downloads),  installed and started the daemon, and had a console window open. After an hour or two of playing at the command …
Learn how to match and substitute tagged data using PHP regular expressions. Demonstrated on Windows 7, but also applies to other operating systems. Demonstrated technique applies to PHP (all versions) and Firefox, but very similar techniques will w…
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…

706 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

Need Help in Real-Time?

Connect with top rated Experts

17 Experts available now in Live!

Get 1:1 Help Now