Note that there are some explanatory texts on larger screens.

plurals
  1. POPerl search and replace enters endless loop
    primarykey
    data
    text
    <p>I am trying to match and replace in multiple files some string using</p> <pre><code>local $/; open(FILE, "&lt;error.c"); $document=&lt;FILE&gt;; close(FILE); $found=0; while($document=~s/([a-z_]+)\.h/$1_new\.h/gs){ $found=$found+1; }; open(FILE, "&gt;error.c"); print FILE "$document"; close(FILE);' </code></pre> <p>It enters an endless loop, because the result of the substitution is matched again by the regular expression searched for. But shouldn't this be avoided by the <code>s///g</code> construct?</p> <p><strong>EDIT:</strong></p> <p>I found that also a <code>foreach</code> loop will not do exactly what I want (it will replace all occurrences, but print only one of them). The reason seems to be that the perl substitution and and search behave quite differently in the <code>foreach()</code> and <code>while()</code> constructs. To have a solution to replace in multiple files which outputs also all individual replacements, I came up with the following <strong>body</strong>:</p> <pre><code># mandatory user inputs my @files; my $subs; my $regex; # additional user inputs my $fileregex = '.*'; my $retval = 0; my $opt_testonly=0; foreach my $file (@files){ print "FILE: $file\n"; if(not($file =~ /$fileregex/)){ print "filename does not match regular expression for filenames\n"; next; } # read file local $/; if(not(open(FILE, "&lt;$file"))){ print STDERR "ERROR: could not open file\n"; $retval = 1; next; }; my $string=&lt;FILE&gt;; close(FILE); my @locations_orig; my @matches_orig; my @results_orig; # find matches while ($string =~ /$regex/g) { push @locations_orig, [ $-[0], $+[0] ]; push @matches_orig, $&amp;; my $result = eval("\"$subs\""); push @results_orig, $result; print "MATCH: ".$&amp;." --&gt; ".$result." @[".$-[0].",".$+[0]."]\n"; } # reverse order my @locations = reverse(@locations_orig); my @matches = reverse(@matches_orig); my @results = reverse(@results_orig); # number of matches my $length=$#matches+1; my $count; # replace matches for($count=0;$count&lt;$length;$count=$count+1){ substr($string, $locations[$count][0], $locations[$count][1]-$locations[$count][0]) = $results[$count]; } # write file if(not($opt_testonly) and $length&gt;0){ open(FILE, "&gt;$file"); print FILE $string; close(FILE); } } exit $retval; </code></pre> <p>It first reads the file creates lists of the matches, their positions and the replacement text in each file (printing each match). Second it will replace all occurrences starting from the end of the string (in order not to change the position of previous messages). Finally, if matches were found, it writes the string back to the file. Can surely be more elegant, but it does what I want.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload