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


By now the question has 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. 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/. This returns true or false in scalar context while in list context it returns the matches. See Extracting Matches. A pattern is best placed into a variable by $patt = qr(...). Our line is in $_ so we need $_ =~ m/$patt/, where m may be omitted. Regex also 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 $varin-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;
    }
    print;
}

The print; uses the same default, $_, and means print $_;. It is after the condition so that all lines are printed, changed or not. A few other errors have been fixed. 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.

6

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