regex — PHP: извлечение цифр и замена всех вхождений из строки на функции

У меня есть эта строка:

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

и я хотел бы заменить все [userid=DIGIT] с displayuser(DIGIT) и все [accountid=DIGIT] с displayaccount(DIGIT),

Таким образом, строка должна выглядеть так:

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

То, что я пробовал до сих пор, который отображает только первый [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);

1

Решение

Вы можете использовать регулярное выражение, которое будет соответствовать и захватывать цифры после userid а также accountid и preg_replace_callback функция это отобразит захваченные значения в необходимые строки внутри анонимной функции обратного вызова, переданной в качестве второго аргумента:

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

Увидеть PHP демо.

\[userid=(\d+)]|\[accountid=(\d+)] шаблон будет соответствовать [userid=<DIGITS_HERE>] размещение цифр в группу 1 или [accountid=<DIGITS_HERE>] поместив эти цифры в группу 2. Использование !empty($m[1]) в обратном вызове мы проверяем, соответствует ли Группа 1, и если да, используем displayuser($m[1]) чтобы получить имя пользователя по идентификатору пользователя, иначе мы используем displayaccount($m[2]) получить имя учетной записи по идентификатору учетной записи.

1

Другие решения

С использованием preg_replace_callback, как предложено @ h2ooooooo, я пришел к следующему, который прекрасно работает

$text = "[userid=77] has created a new task. [userid=59] and [userid=66] is are subscribed. This task is assigned to [accountid=4]";

function displaycontact_cb($matches){
$found2 = preg_match('!\d+!', $matches[0], $match_id);
return displayuser($match_id[0]);
}

function displayaccount_cb($matches){
$found2 = preg_match('!\d+!', $matches[0], $match_id);
return displaycontact($match_id[0],"account");
}

$text = preg_replace_callback('@\[userid[^\]]+\]@',"displaycontact_cb",$text);
$text = preg_replace_callback('@\[accountid[^\]]+\]@',"displayaccount_cb",$text);

print $text;
1

По вопросам рекламы [email protected]