Delicious Bookmark this on Delicious Share on Facebook SlashdotSlashdot It! Digg! Digg



PHP : Function Reference : Regular Expression Functions (Perl-Compatible) : preg_replace_callback

preg_replace_callback

Perform a regular expression search and replace using a callback (PHP 4 >= 4.0.5, PHP 5)
mixed preg_replace_callback ( mixed pattern, callback callback, mixed subject [, int limit [, int &count]] )

The behavior of this function is almost identical to preg_replace(), except for the fact that instead of replacement parameter, one should specify a callback.

Parameters

pattern

The pattern to search for. It can be either a string or an array with strings.

callback

A callback that will be called and passed an array of matched elements in the subject string. The callback should return the replacement string.

You'll often need the callback function for a preg_replace_callback() in just one place. In this case you can use create_function() to declare an anonymous function as callback within the call to preg_replace_callback(). By doing it this way you have all information for the call in one place and do not clutter the function namespace with a callback function's name not used anywhere else.

Example 1723. preg_replace_callback() and create_function()

<?php
/* a unix-style command line filter to convert uppercase
* letters at the beginning of paragraphs to lowercase */
$fp = fopen("php://stdin", "r") or die("can't read stdin");
while (!
feof($fp)) {
   
$line = fgets($fp);
   
$line = preg_replace_callback(
       
'|<p>\s*\w|',
       
create_function(
           
// single quotes are essential here,
           // or alternative escape all $ as \$
           
'$matches',
           
'return strtolower($matches[0]);'
       
),
       
$line
   
);
   echo
$line;
}
fclose($fp);
?>


subject

The string or an array with strings to search and replace.

limit

The maximum possible replacements for each pattern in each subject string. Defaults to -1 (no limit).

count

If specified, this variable will be filled with the number of replacements done.

Return Values

preg_replace_callback() returns an array if the subject parameter is an array, or a string otherwise.

If matches are found, the new subject will be returned, otherwise subject will be returned unchanged.

ChangeLog

Version Description
5.1.0 The count parameter was added

Examples

Example 1724. preg_replace_callback() example

<?php
// this text was used in 2002
// we want to get this up to date for 2003
$text = "April fools day is 04/01/2002\n";
$text.= "Last christmas was 12/24/2001\n";
// the callback function
function next_year($matches)
{
 
// as usual: $matches[0] is the complete match
 // $matches[1] the match for the first subpattern
 // enclosed in '(...)' and so on
 
return $matches[1].($matches[2]+1);
}
echo
preg_replace_callback(
           
"|(\d{2}/\d{2}/)(\d{4})|",
           
"next_year",
           
$text);

?>

The above example will output:

April fools day is 04/01/2003
Last christmas was 12/24/2002


Example 1725. preg_replace_callback() using recursive structure to handle encapsulated 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;
?>


See Also
preg_replace()
create_function()
information about the callback type

Code Examples / Notes » preg_replace_callback

vlad4321

You can use this function to display url address as a link or image based on suffix of the url.
Every string beginning with www or http(s):// will be displayed as an URL address.  But if the string ends with *.jpg or *.gif, it will be displayed as an image.
Please note: This function also verifies the size of the image. If is it more than 600x400, it changes it.
<?php
$pattern_html = "/\b((http(s?):\/\/)|(www\.))([\w\.]+)";
$pattern_html .= "([\#\,\/\~\?\&\=\;\%\-\w+\.]+)\b/i";
$text = preg_replace_callback($pattern_html,'Check_if_Image',$text);
.
.
function Check_if_Image($matches) {
$suffix = strtolower(substr($matches[0],-4));
if ( $suffix == '.jpg' or $suffix == '.gif') {
$dsn = 'http'.$matches[3].'://'.$matches[4].$matches[5];
if (list($width, $height, $type, $attr) = getimagesize("$dsn")) {
if ( ($width > 600) ) {
$koef = $width / 600;
$width = 600;
$height /= $koef;
}
if ( ($height > 400) ) {
$koef = $height / 400;
$height = 400;
$width /= $koef;
}
}
else {
$height=400;
$width=600;
}
$ret = "<img src=\"$dsn\"";
$ret .= "\" border=0 width=\"$width\" height=\"$height\">";
}
else {
$ret = '<a href="http'.$matches[3].'://'.$matches[4].$matches[5];
$ret .='" target="_blank">'.$matches[0].'</a>';
}
return ("$ret");
}
?>


sjon

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 yourself

sjungwirth domain matrix-consultants com

one way to 'pass' extra info other than just the matches and still use preg_replace_callback is to have your callback function be a class method, and just before you call preg_replace_callback, store the info in that class. I am using static methods/variables for my implementation; I'm not sure if its required.
<?php
class foo {
private static $bar;
public static function do_something($bar) {
self::$bar = $bar; // store bar

$input = $bar->get_somevar();
$pattern = "match me";
$output = preg_replace_callback($pattern, array('self', 'do_something_callback'), $input);

return $output;
}
private static function do_something_callback($matches) {
$bar = self::$bar; // retrieve bar

// do stuff like $bar->get_someothervar();

return $replacement;
}
}
?>


matt

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);


vinyanov

If you want to replace your matches with a unique calculation and you do not want to use:
1. preg_replace() and /e flag*
2. preg_replace_callback() and create_function()**
3. preg_replace_callback() and fill the namespace with an additional function
You can insert both call and solution within one function. Then, you may supply callback with the __FUNCTION__ predefined constant, and the function will separate its responsibilities itself by the type of the argument. Since preg_replace_callback() returns an array, this is easy. Quite useless example:
<?php
function debug($s)
{
 if(is_string($s))
 {
   return preg_replace_callback('/{\?(cl|co|f|i|v)}/', __FUNCTION__, $s);
 }
   
 foreach(array(
   'co'  =>'nstants',
   'f'   =>'unctions',
   'v'   =>'ars',
   'cl'  =>'asses',
   'i'   =>'nterfaces',
 ) as $p[1] => $p[2])
 {
   if($p[1] === $s[1])
   {
     $p[0] = in_array($p[1], array('cl', 'i')) ? 'declared' : 'defined';
     $f = vsprintf('get_%3$s_%2$s%1$s', $p); return var_export($f(), 1);
   }
 }
}
echo debug('Variables: {?v} Nothing: {?n} Interfaces: {?i}');
?>
* I do not know whether it evokes eval() or not
** http://tinyurl.com/3azwyy


e-mail

If you want to do a date function in a template system you'll have to use the callback here.
Ex.:
function date_match ($matches)
{
  return date ($matches['2']);
}
$output = preg_replace_callback ('/({DATE=")(.{1,})("})/', 'date_match', $input);


oyoryelnospam

If you want to be able to change variables of the class in the callback function, you have to use preg_replace_callback(pattern, array(&$this, 'method_name'), subject)
Probably very obvious, but it kept me busy for a while...


spamhoneypot

I thought I'd post this as I'd been using the function preg_replace_callback with NP within functions, but as soon as I re-wrote my script as a class, it all fell apart.
When debugging I ended up writing test code and this is what follows. It works as I'd expect, YMMV of course.
<?php
// v v over simplified
class foo
{
 function parse()
 {
   $pattern = "/<a(.*?)href\s*=\s*['|\"|\s*](.*?)['|\"|>](.*?)>(.*?)<\/a>/i";
   $string = "<a class='whatever' href='http://foo.com' target='_blank'>foo</a>";
   print preg_replace_callback($pattern,array($this,'cb'),$string);
 }
 function cb($matches)
 {
   return "<a" . $matches[1] . "href='http://someothersite.com/foo.php?page=" . urlencode($matches[2]) . "'" . $matches[3] . ">" . $matches[4] . "</a>";
 }
}
$bar = new foo();
$bar->parse();
/**
output is
<a class='whatever' href='http://someothersite.com/foo.php?page=http%3A%2F%2Ffoo.com' target='_blank'>foo</a>
*/
?>


ak

Add this snippet to your callback function to make sure you don't replace HTML code. Useful when searching / replacing / highlighting HTML. Change 90 to whatever threshold you need if you have extra extra long tags for some weird reason (lots of inline styles?)
function scanForTags($position, $maintext)
{
for($i = 1;$i < 90; $i++)
{

if($maintext{$position-$i} == "<" || $maintext{$position+$i} == ">")
return true;
if($maintext{$position-$i} == ">" || $maintext{$position+$i} == "<")
return false;
}
return false;
}


roytam

> sjungwirth domain matrix-consultants com
It may fail in nested condition if $bar needs to be changed.


Change Language


Follow Navioo On Twitter
Pattern Modifiers
Pattern Syntax
preg_grep
preg_last_error
preg_match_all
preg_match
preg_quote
preg_replace_callback
preg_replace
preg_split
eXTReMe Tracker