Search code examples
phpregexstringpreg-replacereplaceall

PHP: Extract digits and replacing all occurrences from a string with functions


I have this string:

$string = '[userid=77] has created a new task.
[userid=59] and [userid=66] is are subscribed.
This task is assigned to [accountid=2248]';

and I would like to replace all [userid=DIGIT] with displayuser(DIGIT) and all [accountid=DIGIT] with displayaccount(DIGIT).

So the string should end up like this:

$string = displayuser(77).' has created a new task.
    '.displayuser(59).' and '.displayuser(66).' is are subscribed.
    This task is assigned to '.displayaccount(2248).';

What I tried so far which only displays the first [userid=DIGIT].

$text = "[userid=77] has created a new task. [userid=59] and [userid=66] is are subscribed. This task is assigned to [accountid=28]";
print "Before: ".$text."<br/><br/>";

$matches = array();

// Get [userid=DIGIT]
$found = preg_match('@\[userid[^\]]+\]@', $text, $matches);
print $matches[0]."<br/><br/>";

// Get DIGIT withing [userid=DIGIT]
$found2 = preg_match('!\d+!', $matches[0], $match_id);
echo $match_id[0]."<br/><br/>";

// Replace [userid=DIGIT] with function(DIGIT)
$new = str_replace($matches[0],displayuser($match_id[0]),$text);

Solution

  • You may use a regex that will match and capture the digits after userid and accountid and a preg_replace_callback function that will map the captured values to the necessary strings inside an anonymous callback function passed as the second argument:

    $text = preg_replace_callback('@\[userid=(\d+)]|\[accountid=(\d+)]@', function($m) {
        return !empty($m[1]) ? displayuser($m[1]) : displayaccount($m[2]);
    }, $text);
    

    See the PHP demo.

    The \[userid=(\d+)]|\[accountid=(\d+)] pattern will match [userid=<DIGITS_HERE>] placing the digits into Group 1 or [accountid=<DIGITS_HERE>] placing these digits into Group 2. Using !empty($m[1]) in the callback, we check if Group 1 matched and if yes, use the displayuser($m[1]) to get the user name by user ID, else we use displayaccount($m[2]) to get the account name by account ID.