This is far too complicated to be seriously done with regex, I think...
As long as you have a fixed number of <
between the $
signs, it's easy (See the answer from n-dru).
But here you are:
$output = preg_replace(<<<'REGEX'
(\$\K\s*((?:[^<$\s]+|(?!\s+[<$])\s+)*)\s*(?=(?:<(*ACCEPT)|\$|$)(*SKIP)(*F))
# \$\K => avoid the leading $ in the match
# ((?:[^<$\s]+|(?!\s+[<$])\s+)*) => up to $ or <, excluding surrounding spaces
# (?=(?:<(*ACCEPT)|\$|$)(*SKIP)(*F)) => accept matches with <, reject these without
|(?!^)<\K\s*((?:[^<$\s]+|(?!\s+[<$])\s+)*)\s*(\$|)
# (?!^) => to ensure we are inside $ ... $
# <\K => avoid the leading < in the match
|[^$]+(*SKIP)(*F)
# skip everything outside $ ... $
)x
REGEX
, " $1$2 $3", $your_input);
See also: https://regex101.com/r/fP9aG5/2
I realize, you requested for $x<y<z$
=> $x < y < z$
(instead of $ x < y < z $
), but this is not doable with normal replacement patterns. Would need preg_replace_callback
for that:
$output = preg_replace_callback(<<<'REGEX'
(\$\K\s*((?:[^<$\s]+|(?!\s+[<$])\s+)*)\s*(?=(?:<(*ACCEPT)|\$|$)(*SKIP)(*F))
|(?!^)<\K\s*((?:[^<$\s]+|(?!\s+[<$])\s+)*)\s*(\$|)
|[^$]+(*SKIP)(*F))x
REGEX
, function($m) {
if ($m[1] != "") return "$m[1] ";
if ($m[3] != "") return " $m[2]$m[3]";
return " $m[2] ";
}, $your_input);
I've tried $your_input with:
random < test
nope $ foo $ bar < a $ qux < biz $fx<hk$
$foo<bar<baz$ foo buh < bar < baz $
$ foo $ a < z $ a < b < z $
with this preg_replace_callback, I get, as expected:
random < test
nope $ foo $ bar < a $qux < biz$fx<hk$
$foo<bar<baz$foo buh < bar < baz$
$ foo $ a < z $a < b < z$