You can do it with a single replacement:
$txt = preg_replace('~^(?:TABLE\R|\G(?!\A)(?:END$|.+\R|.+\z))~m', '%$0', $txt);
Note that this pattern assume there's always a closing END "tag". If it isn't the case the replacement will continue until an empty line (cause of the +
quantifier) or the end of the string.
You can also make the choice to check if the TABLE tag is closed with an END tag:
$pattern = '~^(?:TABLE\R(?=(?:.+\R)*?END$)|\G(?!\A)(?:END$|.+\R|.+\z))~m';
First pattern details:
^ # matches the start of a line
(?: # open a non-capturing group
TABLE \R # TABLE and a newline (CR, LF or CRLF)
| # OR
\G (?!\A) # contigous to a precedent match but not
# at the start of the string
(?: #
END $ # END at the end of a line
| #
.+ \R # a line (not empty) and a newline
| #
.+ \z # the last line of the string
) # close the non-capturing group
) #
Additional lookahead details:
(?= # open the lookahead
(?:.+\R)*? # matches zero or more lines lazily
END$ # until the line END
)
An other way
$arr = preg_split('/\R/', $txt);
$state = false;
foreach ($arr as &$line) {
if ($state || $line === 'TABLE') {
$state = ($line !== 'END');
$line = '%' . $line;
}
}
$txt = implode("\n", $arr);
The behaviour of this code is the same as the first pattern, note that you obtain a string with UNIX format newlines.