(PHP 4 >= 4.0.5, PHP 5, PHP 7, PHP 8)
preg_replace_callback — Выполняет поиск по регулярному выражению и заменяет совпадения callback-функцией
$pattern,$callback,$subject,$limit = -1,&$count = null ,$flags = 0
Поведение функции во многом напоминает поведение функции
preg_replace() , за исключением передачи
callback-функции вместо
параметра replacement.
patternИскомый шаблон: строка или массив строк.
callback
Callback-функция для вызова и передачи
массива совпадений, которые функция нашла в строке subject.
Сигнатура callback-функции предусматривает возврат изменённой строки:
При вызове функции preg_replace_callback()
callback-функцию часто вызывают однократно,
поэтому для объявления обратного вызова внутри вызова функции preg_replace_callback()
объявляют анонимную функцию.
При таком способе организации кода информация о вызове собирается в одном месте
и не загромождает текущее пространство имён
названием callback-функции, которая не вызывается в другом месте.
Пример #1 Пример вызова функции preg_replace_callback() с анонимной callback-функцией
<?php
/* Фильтр командной строки в стиле Unix-систем
* для преобразования заглавных букв в начале параграфа в строчные */
$fp = fopen("php://stdin", "r") or die("не удалось прочесть stdin");
while (!feof($fp)) {
$line = fgets($fp);
$line = preg_replace_callback(
'|<p>\s*\w|',
function ($matches) {
return strtolower($matches[0]);
},
$line
);
echo $line;
}
fclose($fp);
?>subjectСтрока или массив строк для поиска и замены.
limit
Максимально возможное количество замен для каждого шаблона
в каждой строке subject. По умолчанию значение
равно -1 (без ограничений).
countПри вызове с этим параметром переменная заполняется количеством замен, которые выполнила функция.
flags
Параметр flags принимает комбинацию флагов
PREG_OFFSET_CAPTURE
и PREG_UNMATCHED_AS_NULL , которые влияют
на формат массива совпадений.
Дополнительную информацию даёт описание функции preg_match() .
Функция preg_replace_callback() возвращает массив,
если в параметр subject передали массив,
иначе возвращает строку. Функция возвращает значение null , если возникла ошибка.
Функция возвращает новую строку, если нашла совпадения,
иначе возвращает строку subject без изменений.
Если передали шаблон регулярного выражения, который не компилируется в допустимое регулярное выражение,
выдаётся ошибка уровня E_WARNING .
| Версия | Описание |
|---|---|
| 7.4.0 |
Добавили параметр flags.
|
Пример #2 Пример использования preg_replace_callback()
<?php
// Текст написали в 2002 году
// и требуется обновить даты на 2003 год
$text = "День смеха отмечали 01/04/2002\n";
$text.= "Последнее Рождество отмечали 24/12/2001\n";
// Callback-функция
function next_year($matches)
{
// Стандартно: $matches[0] — полное вхождение шаблона,
// $matches[1] — вхождение первой подмаски
// в круглых скобках '(...)' и так далее...
return $matches[1].($matches[2]+1);
}
echo preg_replace_callback(
"|(\d{2}/\d{2}/)(\d{4})|",
"next_year",
$text,
);
?>Результат выполнения приведённого примера:
День смеха отмечали 01/04/2003 Последнее Рождество отмечали 24/12/2002
Пример #3 Пример рекурсивной обработки BB-кода функцией preg_replace_callback()
<?php
$input = "верх [indent] глубже [indent] ещё глубже [/indent] глубже [/indent] верх";
function parseTagsRecursive($input)
{
$regex = '#\[indent]((?:[^[]|\[(?!/?indent])|(?R))+)\[/indent]#';
if (is_array($input)) {
$input = '<div style="margin-left: 10px">'.$input[1].'</div>';
}
return preg_replace_callback($regex, 'parseTagsRecursive', $input);
}
$output = parseTagsRecursive($input);
echo $output;
?>
The easiest way to pass more than one parameters to the callback function is with the 'use' keyword.
[This is better than using global, because it works even when we are already inside a function.]
In this example, the callback function is an anonymous function, which takes one argument, $match, supplied by preg_replace_callback(). The extra
"use ($ten)" puts the $ten variable into scope for the function.
<?php
$string = "Some numbers: one: 1; two: 2; three: 3 end";
$ten = 10;
$newstring = preg_replace_callback(
'/(\\d+)/',
function($match) use ($ten) { return (($match[0] + $ten)); },
$string
);
echo $newstring;
#prints "Some numbers: one: 11; two: 12; three: 13 end";
?>preg_replace_callback returns NULL when pcre.backtrack_limit is reached; this sometimes occurs faster then you might expect. No error is raised either; so don't forget to check for NULL yourselfIf you want to call non-static function inside your class, you can do something like this.
For PHP 5.2 use second argument like array($this, 'replace'):
<?php
class test_preg_callback{
private function process($text){
$reg = "/\{([0-9a-zA-Z\- ]+)\:([0-9a-zA-Z\- ]+):?\}/";
return preg_replace_callback($reg, array($this, 'replace'), $text);
}
private function replace($matches){
if (method_exists($this, $matches[1])){
return @$this->$matches[1]($matches[2]);
}
}
}
?>
For PHP 5.3 use second argument like "self::replace":
<?php
class test_preg_callback{
private function process($text){
$reg = "/\{([0-9a-zA-Z\- ]+)\:([0-9a-zA-Z\- ]+):?\}/";
return preg_replace_callback($reg, "self::replace", $text);
}
private function replace($matches){
if (method_exists($this, $matches[1])){
return @$this->$matches[1]($matches[2]);
}
}
}
?>A simple function to replace a list of complete words or terms in a string (for PHP 5.3 or above because of the closure):
<?php
function replace_words($list, $line, $callback) {
return preg_replace_callback(
'/(^|[^\\w\\-])(' . implode('|', array_map('preg_quote', $list)) . ')($|[^\\w\\-])/mi',
function($v) use ($callback) { return $v[1] . $callback($v[2]) . $v[3]; },
$line
);
}
?>
Example of usage:
<?php
$list = array('php', 'apache web server');
$str = "php and the apache web server work fine together. php-gtk, for example, won't match. apache web servers shouldn't too.";
echo replace_words($list, $str, function($v) {
return "<strong>{$v}</strong>";
});
?>it is much better on preformance and better practice to use the preg_replace_callback function instead of preg_replace with the e modifier.
function a($text){return($text);}
// 2.76 seconds to run 50000 times
preg_replace("/\{(.*?)\}/e","a('\1円','\2円','\3円',\$b)",$a);
// 0.97 seconds to run 50000 times
preg_replace_callback("/\{(.*?)\}/s","a",$a);<?php
// Nice little function that convert a string to uppercase by keeping the HTMLentities intact.
public static function strtoupper_entities($str) {
$patternMajEntities = '/(\&([A-Z])(ACUTE|CEDIL|CARON|CIRC|GRAVE|ORN|RING|SLASH|TH|TILDE|UML)\;)+/';
$str = preg_replace_callback ($patternMajEntities,
function ($matches) {
return "&" . $matches[2] . strtolower($matches[3]) . ";";
}, strtoupper($str));
return $str;
}The good version of the class PhpHex2Str
<?php
class PhpHex2Str
{
private $strings;
private static function x_hex2str($hex) {
$hex = substr($hex[0], 1);
$str = '';
for($i=0;$i < strlen($hex);$i+=2) {
$str.=chr(hexdec(substr($hex,$i,2)));
}
return $str;
}
public function decode($strings = null) {
$this->strings = (string) $strings;
return preg_replace_callback('#\%[a-zA-Z0-9]{2}#', 'PhpHex2Str::x_hex2str', $this->strings);
}
}
// Exemple
$obj = new PhpHex2Str;
$strings = $obj->decode($strings);
var_dump($strings);
?>Text lines numeration:
<?PHP
// Multieline text:
$Text = "
Some
Multieline
text
for
numeration";
// For count:
$GLOBALS["LineNUMBER"] = 1;
// Replace linestart on number:
PRINT preg_replace_callback("/^/m",function ()
{
return $GLOBALS["LineNUMBER"]++." ";
},
$Text);
?>
1
2 Some
3 Multieline
4 text
5 for
6 numerationFrom PHP 5.3 you can use an anonymous function to pass local variables into the callback.
<?php
public function replace_variables( $subject, $otherVars ) {
$linkPatterns = array(
'/(<a .*)href=(")([^"]*)"([^>]*)>/U',
"/(<a .*)href=(')([^']*)'([^>]*)>/U"
);
$callback = function( $matches ) use ( $otherVars ) {
$this->replace_callback($matches, $otherVars);
};
return preg_replace_callback($this->patterns, $callback, $subject);
}
public function replace_callback($matches, $otherVars) {
return $matches[1] . $otherVars['myVar'];
}
?><?php
$format = <<<SQL
CREATE DATABASE IF NOT EXISTS :database;
GRANT ALL PRIVILEGES ON :database_name.* TO ':user'@':host';
SET PASSWORD = PASSWORD(':pass');
SQL;
$args = ["database"=>"people", "user"=>"staff", "pass"=>"pass123", "host"=>"localhost"];
preg_replace_callback("/:(\w+)/", function ($matches) use ($args) {
return @$args[$matches[1]] ?: $matches[0];
}, $format);
/*
Result:
CREATE DATABASE IF NOT EXISTS people;
GRANT ALL PRIVILEGES ON :database_name.* TO 'staff'@'localhost';
SET PASSWORD = PASSWORD('pass123');
The `:database_name` placeholder doesn't exist as a matching key in `$args` so it's returned as is.
This way you know you need to correct the array by adding the "database_name" item.
*/The pcre.backtrack_limit option (added in PHP 5.2) can trigger a NULL return, with no errors. The default pcre.backtrack_limit value is 100000. If you have a match that exceeds about half this limit it triggers a NULL response.
e.g. My limit was at 100000 but 500500 triggered a NULL response. I'm not running unicode but I *guess* PCRE runs in utf-16.