In the second example you're trying to match
<p></p> directly, with an additional assertion.
Try
/<p>(?=.*?\[tab\]).*?<\/p>/ instead. But that doesn't check if the
[tab] occurs before the
</p>, so don'T try to mess with lookarounds but use your first pattern.
Update: OK, that doesn't fix your real problem. I'll have to think a bit more about it. In this simple case you can just use [^<>] instead of a dot everywhere between <p> and </p>.
The old truth that HTML shouldn't be parsed with regexes still holds.