Ohne U sind Wiederholungsoperatoren per Default greedy, mit der U Option werden sie per Default lazy. Es gibt darüber hinaus die Möglichkeit, dem Wiederholungsoperator ein ? nachzustellen, um pro Operator zwischen greedy und lazy umzuschalten. Ich habe das in meinem Vorschlag unten mal gemacht. Muss man nicht.
An Stelle von * gibt es noch das +, um mindestens ein Match zu haben. Du kannst ..* durch .+ ersetzen. Du kannst aber auch einfach .* schreiben, weil <p></p>
dank der negativen Assertion sowieso nicht gematcht wird.
Und das / brauchst Du nicht zu escapen, wenn Du einen anderen Regex-Delimiter nimmst. Z.B.:
@<p>(?!</p>).*?</p>@i
Ist es eigentlich wirklich deine Absicht, <p></p>
nicht zu matchen?
Und ich frage mich noch, ob Du die g Option hinzufügen musst (global), um mehr als einen Paragraphen zu replacen.
Hier kannst Du übrigens spielen.
Rolf