Abhishek Abhishek - 1 year ago 58
Perl Question

How to do multiple value replacement in a multiple line at one time

Lets say I have multiples like this

My input lines:

"stack overflow version {5} my new version"
"stack exchnage version {10} my new version"
"perl scripting version 5.14 my new version"
"segmentaion falult happen {5} if the memory is not freed"
" my college 30 new xxxx"

I want to replace value inside parenthesis in all line at one time.

My Approaches:

use strict;
use warnings;
my $old_parameter='stack overfolw version';
my $new_parameter;
my $old_value={5};
my $new_value='20 ';
my $filename ='input.txt'

open my $fh, "<", $filename or die "Couldn't open input file: $!";

while ( <$fh> )
if (/$old_parameter/ and /$old_value/)


stack overflow version {20} my new version; #values change from 5 to 20

Now I have hard coded the value which is 20 but what I am looking for I will store the value (1..100) into some array from there I will pick the value based on each line that I want to replace.

For that I need to match line then I have to do replace.

Then what would be the best approach ?

Answer Source

By now the question assumed form. I take it that you want to change the number in { } on a particular line in the file. The posted code got close and I'll comment on basics and complete it.

Since we now find the number inside { } there is no need for the hard-coded $old_value and it goes away. In order to identify the desired line you need to match the $old_parameter so the condition becomes if (/$old_parameter/). A comment on regex matching follows, related only to what is used in the code. Please read documentation and books for more.

Consider while (my $line = <$fh>). A line is read from the file via $fh by the diamond operator <> and assigned to a variable $line. If you leave out the variable and write only while (<$fh>) then the line is assigned to a special variable called $_. This variable is often used as a default in Perl. See General Variables.

To check whether a pattern is in a variable, to "match" it, we say $var =~ m/$patt/. A pattern is best placed into a variable by $patt = qr(...). Our line is in $_ so we need $_ =~ /$patt/ (m may be omitted). But regex allows a shortcut, since it works by default on $_, and we may say /$patt/. Thus if (/.../).

Now consider substitution. To find a pattern and replace it we say $var =~ s/$patt/$repl/. This changes $var "in-place", meaning that after that statement $var is changed. If the $patt wasn't found in $var nothing happens to it. With our line in $_ we again need $_ instead of $var, but the same shortcut works and we can say s/$patt/$repl/.

Your code has this – but it doesn't do anything with it. The result is never given by the program. An easy way is to print every line and the output can be redirected to a file. Or write lines to a file.

Now for the needed regex. You want a number inside of { }. According to the data you show it is the only such pattern in the line. Then this will do

s/ \{ \s* \d+ \s* \} /{$new_value}/x;

The /x allows us to use spaces for readibilty. (Otherwise they would be looked for in the string!) A digit is matched by \d, and + means all that come together, but at least one. In a123b it matches 123, in a12b3c it matches 12. The { and } are escaped since they have a special meaning in a regex. The \s* allows for any number of spaces, or for none.

The replacement side of the regex says to replace all that has been matched with {$new_value}. There we don't have to escape { }. If you need to capture (remember) what has been matched place the pattern in between (). Here you can say

s/ (\{ \s*) (\d+) (\s* \}) /$1$new_value$3/x;

and have the original spaces preserved. The first capture is stored in $1, the second in $2, etc. If the $new_value changes during the loop you can compute it before the substitution.

Please see the answer by Schwern and the technique offered in a comment by ikegami.

Then we only need to print the line. The full program

use warnings 'all';
use strict;

my $old_parameter = 'stack overflow version';
my $new_value = 20;

my $filename = 'input.txt';

open my $fh, "<", $filename or die "Can't open $filename: $!";

while ( <$fh> ) 
    if (/$old_parameter/) 
        s/\{\s* (\d+) \s*\}/{$new_value}/x;

The print; uses the same default, $_, and means print $_;. It is after the condition so that all lines are printed, changed or not. Note that a few other errors have been fixed, too. An amusing one is the following: your $old_parameter has "stack overfolw version" (misspelled) so it never matches the line.

Finally, please read through perlretut, or better yet, through a nice chapter on regular expressions from a book or a tutorial that you are working with.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download