1

I would like to replace a space after a number with hard-space " " only in p tags.

I wrote this code:

   $pattern = "/<p>[0-9] <\/p>/";
   return preg_replace($pattern, "$1&nbsp;", $text);

But it does nothing, why? Can you please help?

Example:

Input : "My 90 days work."
Output: "My 90&nbsp;days work."

Thank you a lot.

Wiktor Stribiżew
  • 607,720
  • 39
  • 448
  • 563
Josef Kuchař
  • 51
  • 1
  • 4

2 Answers2

1

Try this:

$text = '<p>My 90 days 123 work.</p>';
$pattern = "/<p>(.*?)<\/p>/";
$text = preg_replace_callback($pattern, function ($matches) {
    $content = $matches[1];
    $content = preg_replace('/(\d+)\s/', '$1&nbsp;', $content);
    return "<p>{$content}</p>";
}, $text);
Baekhan Sung
  • 127
  • 6
1

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, "&nbsp", $str);

Output

<p>My 90&nbspdays 123&nbspwork.</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/", "&nbsp", $p->nodeValue);
}

Output

My 90&nbspdays 123&nbspwork.
The fourth bird
  • 154,723
  • 16
  • 55
  • 70