Matching html with a regex is not advisable, but if there can be no angle brackets in between, you might get away with a single pattern using the \G
anchor:
(?:<p>(?=[^<>]*</p>)|\G(?!^))[^\d<>]*\d+\K\h
Explanation
(?:
Non capture group
<p>(?=[^<>]*</p>)
Match <p>
and assert a closing </p>
without angle brackets in between
|
Or
\G(?!^)
Assert the current position at the end of the previous match, but not at the start of the string
)
Close the non capture group
[^\d<>]*
Match optional chars other than <
or >
or a digit
\d+
Match 1+ digits
\K
Forget what is matched so far
\h
Match a single horizontal whitespace char
See a regex demo and a PHP demo.
$re = '~(?:<p>(?=[^<>]*</p>)|\G(?!^))[^\d<>]*\d+\K\h~';
$str = '<p>My 90 days 123 work.</p>';
echo preg_replace($re, " ", $str);
Output
<p>My 90 days 123 work.</p>
Or using DOMDocument to find the paragraphs, and do the replacement after matching a digit and a horizontal whitespace char:
$str = '<p>My 90 days 123 work.</p>';
$domDoc = new DOMDocument;
$domDoc->loadHTML($str, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
foreach ($domDoc->getElementsByTagName('p') as $p) {
echo preg_replace("/\d\K\h/", " ", $p->nodeValue);
}
Output
My 90 days 123 work.