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 $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;
}
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