preg_replace variable replacement showing error with single quotes

277 views Asked by At

I have this preg_replace statement,

$s = "Foo money bar";
echo preg_replace("/(office|rank|money)/i", "<strong>$1</strong>", $s);

Which returns,

Foo <strong>money</strong> bar 

However when I try doing the exact same thing with single quotes and with a function being used on $i it breaks,

$s = "Foo money bar";
echo preg_replace("/(office|rank|money)/i", '<strong>' . ucfirst($1) . '</strong>', $s);

Note the single quotes in the second parameter of the function, this now yields,

syntax error, unexpected '1' (T_LNUMBER), expecting variable (T_VARIABLE) or '{' or '$'

Live Example

Double Quotes

Single Quotes

So my question is why does this occur and how could I get the expected output (strong with ucfirst) as shown in the second example?

Update #1

This issue is happening not only because of the function ucfirst but due to the single quotes too as can be seen in this example,

$s = "Foo money bar";
echo preg_replace("/(office|rank|money)/i", '<strong>' . $1 . '</strong>', $s);

Output

syntax error, unexpected '1' (T_LNUMBER), expecting variable (T_VARIABLE) or '{' or '$'
2

There are 2 answers

8
Casimir et Hippolyte On BEST ANSWER

You can't use a function in the second parameter of preg_replace.
'<strong>' . ucfirst($1) . '</strong>' is evaluated before the search. To use a function in a regex replacement, you have to use preg_replace_callback:

$result = preg_replace_callback($pattern, function ($m) {
    return '<strong>' . ucfirst($m[1]) . '</strong>';
}, $yourstring);
4
ishegg On

You're getting that error not because of the type of quotes, but because you're doing it outside the quotes.

echo preg_replace("/(office|rank|money)/i", "<strong>" . $1 . "</strong>", $s);

This throws the same error. That's because $1 is not a variable, it's a back reference. You can refer to it as \1 instead of $1 and it'll be clearer.

So, you can't refer to the back reference outside the quotes (besides, $1 would be an illegal variable name). I can't refer to the specific internals on how this works (couldn't find anything), but it probably is set as a "flag" for the interpreter to replace with the nth matching group.

Interestingly, if you use a function as the second parameter and wrap the back reference in quotes, it still works! (In the sense that it won't error out. It still won't run the function.)

<?php
$s = "Foo money bar";
echo preg_replace("/(office|rank|money)/i", '<strong>' . ucfirst('$1') . '</strong>', $s); // works with single and double quotes

Demo

This article doesn't talk about this but it's a great read anyway.