(PHP 4 >= 4.0.5, PHP 5, PHP 7, PHP 8)
preg_replace_callback — Buscar y reemplazar mediante expresión regular estándar utilizando una función de retrollamada
$pattern,$callback,$subject,$limit = -1,&$count = null ,$flags = 0
El comportamiento de esta función es casi
idéntico al de preg_replace() , con la excepción de que
en lugar del argumento replacement, se debe
especificar una función de retrollamada callback
que será llamada con los elementos encontrados como argumentos.
patternEl patrón a buscar. Puede ser una cadena o un array que contenga cadenas.
callback
La función de retrollamada que recibirá el array de elementos
encontrados en la cadena subject.
La función de retrollamada debe devolver la cadena de
reemplazo. Esta es la firma de la función de retrollamada:
Con frecuencia, la función callback se utiliza
con preg_replace_callback() en un solo lugar.
En este caso, puede simplemente utilizar una
función anónima
para declarar una función de retrollamada para
preg_replace_callback().
Al hacer esto, se concentran todas las rutinas relacionadas con
el reemplazo en un solo lugar, y no se contamina el espacio de nombres de funciones con funciones de un solo uso.
Ejemplo #1 preg_replace_callback() y función anónima
<?php
// Un filtro de línea de comandos Unix para convertir la primera letra
// de los párrafos (que comienzan con "<p>") a minúscula
$fp = fopen("php://stdin", "r") or die("No se puede leer la línea de comandos");
while (!feof($fp)) {
$line = fgets($fp);
$line = preg_replace_callback(
'|<p>\s*\w|',
function ($matches) {
return strtolower($matches[0]);
},
$line
);
echo $line;
}
fclose($fp);
?>subjectLa cadena o el array de cadenas a buscar y reemplazar.
limit
El número máximo de reemplazos para cada patrón
en cada cadena subject.
Por omisión, vale -1 (sin límite).
countSi se proporciona, esta variable será rellenada con el número de reemplazos realizados.
flags
flags puede ser una combinación de los indicadores
PREG_OFFSET_CAPTURE y
PREG_UNMATCHED_AS_NULL , que influyen en el formato
del array de coincidencias.
Consulte la descripción de preg_match() para más detalles.
preg_replace_callback() devuelve un array si el argumento
subject es un array, o de lo contrario, una cadena.
Si ocurre un error, el valor devuelto será null .
Si se encuentran coincidencias, se devuelve el nuevo sujeto, de lo contrario
subject se devuelve sin cambios.
Si el patrón regex pasado no se compila a una regex válida, se emite una E_WARNING .
| Versión | Descripción |
|---|---|
| 7.4.0 |
Se añadió el argumento flags.
|
Ejemplo #2 Ejemplo con preg_replace_callback()
<?php
// Este texto era cierto en 2002
// queremos actualizarlo para 2003
$text = "El primer abril es el 04/01/2002\n";
$text.= "La última navidad fue el 12/24/2001\n";
// Función de retrollamada
function next_year($matches)
{
// como de costumbre: $matches[0] representa el valor total
// $matches[1] representa el primer paréntesis capturante
return $matches[1].($matches[2]+1);
}
echo preg_replace_callback(
"|(\d{2}/\d{2}/)(\d{4})|",
"next_year",
$text);
?>El ejemplo anterior mostrará:
El primer abril es el 04/01/2003 La última navidad fue el 12/24/2002
Ejemplo #3 Ejemplo con preg_replace_callback() utilizando una estructura recursiva para manejar BB code
<?php
$input = "plain [indent] deep [indent] deeper [/indent] deep [/indent] plain";
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.