[Webinar] Streamline your web hosting managementRegister Today

x
?
Solved

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

Posted on 2012-04-09
11
Medium Priority
?
438 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
[Webinar] Kill tickets & tabs using PowerShell

Are you tired of cycling through the same browser tabs everyday to close the same repetitive tickets? In this webinar JumpCloud will show how you can leverage RESTful APIs to build your own PowerShell modules to kill tickets & tabs using the PowerShell command Invoke-RestMethod.

 

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 85

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

Get your problem seen by more experts

Be seen. Boost your question’s priority for more expert views and faster solutions

Question has a verified solution.

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

Do you hate spam? I do, and I am willing to bet you do as well. I often wonder, though, "if people hate spam so much, why do they still post their email addresses on the web?" I'm not talking about a plain-text posting here. I am referring to the fa…
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 …
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
Suggested Courses

591 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