in reply to Efficient method to replace middle lines only when no match

A line-by-line approach might actually be more efficient/maintainable, but if the file's already slurped, maybe something like this (needs Perl 5.10+ for  \K but this could be worked around):

c:\@Work\Perl\monks>perl -wMstrict -le "use 5.010; ;; my $s = qq{yada\n} . qq{field1: valueA\n} . qq{some\n} . qq{lines\n} . qq{here\n} . qq{field3: valueC\n} . qq{blah blah\n} ; print qq{[[$s]]}; ;; my $replace = qq{field2: valueB\n}; ;; $s =~ s{ ^ field1: \s valueA \n \K (?! \Q$replace\E) .*? (?= field3: \s valueC \n) } {$replace}xmsg; print qq{[[$s]]}; " [[yada field1: valueA some lines here field3: valueC blah blah ]] [[yada field1: valueA field2: valueB field3: valueC blah blah ]]

Update 1: Changed  (?! $replace) to  (?! \Q$replace\E)

Update 2: I don't know if I just missed it or it was added after I began my reply, but the code at the bottom of the OP looks a lot like my post, and in fact is better since it takes care of variable value fields as mine does not. ?!?

Replies are listed 'Best First'.
Re^2: Efficient method to replace middle lines only when no match
by Zu (Initiate) on Mar 20, 2014 at 06:54 UTC

    Thanks for using \K in your post, it made me think a bit more and I came up with a solution that doesn't have a penalty when there's a negative match:

    # slow no longer my $has_field2 = "field1: valueA\nfield2: valueB\nfield3: valueC\n"; $has_field2 .= "........................................\n" x 1000; $has_field2 =~ s/field1:[\n]*\n\K(?!field2:).*(?=\nfield3:) /field2: valueB /msx;

    Also, I didn't edit my original post.

      $has_field2 =~ s/field1:[\n]*\n\K(?!field2:).*(?=\nfield3:) /field2: valueB /msx;

      1. Shouldn't the  [\n]*\n after  field1: in the search pattern be  [^\n]*\n (negated class) instead?
      2. The  .* in the search pattern is greedy. Your test string has only one occurrence of the  "field1: valueA\nfield2: valueB\nfield3: valueC\n" substring. What happens if you test against many occurrences (see below — BTW, I have an updated version of this script that, among other things, uses hi-res timing if you're interested)? Won't the greedy  .* just gobble all intervening occurrences?
      3. You have a newline and a lot of blank space in your replacement string; is this what you want?
        c:\@Work\Perl\monks\Zu>perl -wMstrict -le "my $s = 'xxxyxxx'; $s =~ s/y /FOO /xms; print qq{'$s'}; " 'xxxFOO xxx'