Ok, with a better understanding of the requirements, here's a solution that seems sufficiently fast: I'm just timing to 1 sec resolution, but in general, s/// with replacements is a little over 1 sec, without replacements a little under. To me, that seems pretty fast for a 21M timing test string.
use warnings;
use strict;
local $/;
my $slurp = do { local $/; <DATA>; };
print qq{[[$slurp]] \n\n};
my $replace = qq{field2: valueB\n};
my $text = $slurp;
$text =~
s{ ^ field1: [^\n]* \n \K
(?! ^ \Q$replace\E) .*?
(?= ^ field3: [^\n]* \n)
}
{$replace}xmsg;
print qq{[[$text]] \n\n};
$text = $slurp;
$text = $text x 100_000;
printf qq{length of timing string: %d \n\n}, length $text;
print qq{begin timings \n};
my $start = time(); # start timing for replacements
$text =~
s{ ^ field1: [^\n]* \n \K
(?! ^ \Q$replace\E) .*?
(?= ^ field3: [^\n]* \n)
}
{$replace}xmsg;
printf qq{replacements: %ds elapsed \n}, time() - $start;
$start = time(); # start timing for no replacements
$text =~
s{ ^ field1: [^\n]* \n \K
(?! ^ \Q$replace\E) .*?
(?= ^ field3: [^\n]* \n)
}
{$replace}xmsg;
printf qq{no replacements: %ds elapsed \n}, time() - $start;
print qq{\n};
print substr($text, 0, 250), qq{\n... \n}, substr($text, -250), qq{\n}
+;
__DATA__
yada
field1: replace following A
some
lines
here
field3: replace previous A
blah blah
field1: do not replace
field2: valueB
field3: do not replace
field1: replace after B
hoo ha
fee fie foe
field3: replace before B