Categories
PHP

Search & Replace with Multiple Patterns and Callbacks

Learn how to use preg_replace_callback_array() and preg_replace_callback() functions to perform a regular expression search and replace using callbacks.

preg_replace_callback()

//Syntax
<?php
 preg_replace_callback(
    string|array $pattern,
    callable $callback,
    string|array $subject,
    int $limit = -1,
    int &$count = null,
    int $flags = 0
 ): string|array|null

The preg_replace_callback() function takes six parameters:

  1. $pattern: The regular expression as a string or a string array to search for.
  2. $callback: The callback function, pass the function name as a string or use an anonymous function to declare the callback.
  3. $subject: The input string or array to search through.
  4. $limit (optional): The maximum possible replacements, default to -1 (no limit).
  5. &$count (optional): If specified, this variable will be filled with the number of replacements done.
  6. $flags (optional): A combination of the PREG_OFFSET_CAPTURE and PREG_UNMATCHED_AS_NULL flags, see preg_match() tutorial for more details.

This function works the same as the preg_repalce() except that it takes the $callback function instead of the $replacement string.

The callback function will be called and passed an array of matched elements in the subject string. The first element of the array contains the whole matched text, and additional array elements contain any matched subpatterns. See the following example:

<?php
 $subject = '$100';
 $pattern = '/(\$)([0-9]+)/';
 $newStr = preg_replace_callback($pattern, 'CB', $subject);

 function CB($m) {
  echo $m[0].'<br>'; # $100 - the complete match
  echo $m[1].'<br>'; # $ - first subpattern match
  echo $m[2].'<br>'; # 100 - second subpattern match
 }

You can change the matched text with your own algorithm and return the changed text as the replacement text. See the following example, we just created a currency conversion tool that converts the USD to EUR from the subject:

<?php
 $subject = 'Sum of $100 and $50 is $150';
 $pattern = '/(\$)([0-9]+)/';
 $newStr = preg_replace_callback($pattern, 'CB', $subject);
 
 function CB($m) {
  $euro = $m[2] * 0.98;
  return '€'.$euro;
 }
 
 echo $newStr;
 #Prints: Sum of €98 and €49 is €147

Instead of using a regular function as the callback you can use an anonymous function:

<?php
 $subject = 'Sum of $100 and $50 is $150';
 $pattern = '/(\$)([0-9]+)/';
 $newStr = preg_replace_callback(
            $pattern, 
            function ($m){
              $euro = $m[2] * 0.98;
              return '€'.$euro;
             },
            $subject, -1, $count
          );
 
 echo $subject .'<br>'. $newStr .'<br>';
 echo 'No. of changes: '.$count;

/* Sum of $100 and $50 is $150
   Sum of €98 and €49 is €147 
   No. of changes: 3
*/

Since PHP 7.4, you can also use arrow function as it has a more concise syntax:

<?php
 $subject = 'Sum of $100 and $50 is $150';
 $pattern = '/(\$)([0-9]+)/';
 $newStr = preg_replace_callback(
            $pattern, 
            fn($m) => '€' . $m[2] * 0.98,
            $subject, -1, $count
          );
 
 echo $subject .'<br>'. $newStr .'<br>';
 echo 'No. of changes: '.$count;

/* Sum of $100 and $50 is $150
   Sum of €98 and €49 is €147 
   No. of changes: 3
*/

preg_replace_callback_array()

<?php
 //Syntax
 preg_replace_callback_array(
    array $pattern,
    string|array $subject,
    int $limit = -1,
    int &$count = null,
    int $flags = 0
 ): string|array|null

The preg_replace_callback_array() function takes five parameters:

  1. $pattern: An associative array mapping patterns (keys) to callables (values).
  2. $subject: The input string or array to search through.
  3. $limit (optional): The maximum possible replacements, default to -1 (no limit).
  4. &$count (optional): If specified, this variable will be filled with the number of replacements done.
  5. $flags (optional): A combination of the PREG_OFFSET_CAPTURE and PREG_UNMATCHED_AS_NULL flags, see preg_match() tutorial for more details.

The preg_replace_callback_array() function introduced in PHP 7. This function allows you to specify an array of patterns (regular expressions) as keys, with the value representing an independent callback function.

When a pattern (array key) matched, the corresponding callback function will be called and passed an array of matched elements in the subject string.

Similar to the preg_replace_callback() function the first element of the array contains the whole matched text, and additional array elements contain any matched subpatterns. In the following example, we created a separated pattern for each currency, and when the specific currency pattern matched, its value, a callback function, executes:

<?php
 $subject = 
    'Sum of $100 and $50 is $150 <br>
     Sum of ₹7957 and ₹3979 is ₹11936 <br>
     Sum of £82 and £41 is £123';

 $pattern = ['/\$([0-9]+)/' => 'usdToEur',
             '/\£([0-9]+)/' => 'gbpToEur',
             '/\₹([0-9]+)/' => 'inrToEur' ];
 
 $newStr = preg_replace_callback_array($pattern, $subject);
 
 function usdToEur($m) {
  return '€'. $m[1] * 0.98;
 }
 function inrToEur($m) {
  return '€'. $m[1] * 0.012;
 }
 function gbpToEur($m) {
  return '€'. $m[1] * 1.19;
 }
 
 echo $newStr;
/*Prints:
Sum of €98 and €49 is €147
Sum of €95.484 and €47.748 is €143.232
Sum of €97.58 and €48.79 is €146.37*/

Example: Using anonymous functions with preg_replace_callback_array:

<?php
 $subject = 
    'Sum of $100 and $50 is $150 <br>
     Sum of ₹7957 and ₹3979 is ₹11936 <br>
     Sum of £82 and £41 is £123';

 $pattern = [
    '/\$([0-9]+)/' => function ($m) {return '€'. $m[1] * 0.98;},
    '/\£([0-9]+)/' => function ($m) {return '€'. $m[1] * 1.19;},
    '/\₹([0-9]+)/' => function ($m) {return '€'. $m[1] * 0.012;}];
 
 $newStr = preg_replace_callback_array($pattern, $subject);

 echo $newStr;
/*Prints:
Sum of €98 and €49 is €147
Sum of €95.484 and €47.748 is €143.232
Sum of €97.58 and €48.79 is €146.37*/

Example: PHP 7.4 allows you to use arrow functions:

<?php
 $subject = 
    'Sum of $100 and $50 is $150 <br>
     Sum of ₹7957 and ₹3979 is ₹11936 <br>
     Sum of £82 and £41 is £123';

 $pattern = [
    '/\$([0-9]+)/' => fn ($m) => '€'. $m[1] * 0.98,
    '/\£([0-9]+)/' => fn ($m) => '€'. $m[1] * 1.19,
    '/\₹([0-9]+)/' => fn ($m) => '€'. $m[1] * .012];
 
 $newStr = preg_replace_callback_array($pattern, $subject);

 echo $newStr;
/*Prints:
Sum of €98 and €49 is €147
Sum of €95.484 and €47.748 is €143.232
Sum of €97.58 and €48.79 is €146.37*/

More Regular Expressions Tutorials: