Since you didn't define what you call a "boundary", I assumed (from your tests) it means that the searched substring can be surrounded with spaces, punctuation characters and limits of the string. To express that I used negative lookarounds:
(?<![^\s\pP])
(not preceded with a character that isn't a space or a punctuation character)
(?![^\s\pP])
(not followed with a character that isn't a space or a punctuation character)
Note that I used negative lookarounds (instead of (?<=[\s\pP])
and (?=[\s\pP])
) to implicitly include cases where the searched string begins or ends at one of the limits of the string. In other words:
(?<![^\s\pP])
<=> (?<=[\s\pP]|^)
(?![^\s\pP])
<=> (?=[\s\pP]|$)
Code:
$text = 'This is a test èsàdò string123?';
$needles = ['èsàDò', 'a TEST èsàdò', 'string123', 'string12', 'This is a test èsàdò String123?'];
$format = " %-35s\t%s%s";
echo 'TEST STRING: ', $text, PHP_EOL, PHP_EOL;
printf($format, 'needle', 'result', PHP_EOL);
echo str_repeat('-', 50), PHP_EOL;
foreach ($needles as $needle) {
$pattern = '~(?<![^\s\pP])' . preg_quote($needle, '~') . '(?![^\s\pP])~iu';
printf($format, $needle, (preg_match($pattern, $text) ? 'true' : 'false'), PHP_EOL);
}
Result:
TEST STRING: This is a test èsàdò string123?
needle result
--------------------------------------------------
èsàDò true
a TEST èsàdò true
string123 true
string12 false
This is a test èsàdò String123? true