Solved

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

Posted on 2012-04-09
11
413 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
Master Your Team's Linux and Cloud Stack!

The average business loses $13.5M per year to ineffective training (per 1,000 employees). Keep ahead of the competition and combine in-person quality with online cost and flexibility by training with Linux Academy.

 

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 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

PRTG Network Monitor: Intuitive Network Monitoring

Network Monitoring is essential to ensure that computer systems and network devices are running. Use PRTG to monitor LANs, servers, websites, applications and devices, bandwidth, virtual environments, remote systems, IoT, and many more. PRTG is easy to set up & use.

Question has a verified solution.

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

Suggested Solutions

Title # Comments Views Activity
Put query string from URL request -  PERL HTTP Daemon 2 77
Perl string filter 5 79
Is it true to say that Python is successor of Perl? 7 173
regx  exclude  pattern 6 39
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 …
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…

770 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