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

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

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

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