David T-G
David T-G

Reputation: 15

preg_replace arrays with multiple patterns per replacement

I don't think I can do this in one swell foop, but I'm not above asking :-)

I can certainly define one-to-one $pattern and $replacement arrays, and I can repeatedly define $pattern arrays and $replacement strings, but can I do both at once?

Suppose I have three sets like:

$p1 = array('sis','boom','bah');
$r1 = 'cheers';

$p2 = array('boo','hiss');
$r2 = 'jeers';

$p3 = array('guinness','heineken','budweiser');
$r3 = 'beers';

and I'd like to replace in a single large haystack all instances of patterns with their respective single replacements. Is there a single preg_replace call that I can define to accomplish this?

Upvotes: 1

Views: 1714

Answers (2)

mickmackusa
mickmackusa

Reputation: 47992

I think you will need to incorporate word boundaries with a regex-based function.

Consider this strtr() demo:

$string="Rah rah, sis boom bah, I read a book on budweiser";
$p1 = array('sis','boom','bah');
$r1 = 'cheers';
$p2 = array('boo','hiss');
$r2 = 'jeers' ;
$p3 = array('guinness','heineken','budweiser');
$r3 = 'beers';

$replacements=array_merge(
    array_combine($p1,array_fill(0,sizeof($p1),$r1)),
    array_combine($p2,array_fill(0,sizeof($p2),$r2)),
    array_combine($p3,array_fill(0,sizeof($p3),$r3))
);
echo strtr($string,$replacements);

Output:

Rah rah, cheers cheers cheers, I read a jeersk on beers
//                                      ^^^^^ Oops

You will just need to implode your needle elements using pipes and wrap them in a non-capturing group so that the word boundaries apply to all substrings, like this:

Code: (Demo)

$string="Rah rah, sis boom bah, I read a book on budweiser";
$p1 = ['sis','boom','bah'];
$r1 = 'cheers';
$p2 = ['boo','hiss'];
$r2 = 'jeers' ;
$p3 = ['guinness','heineken','budweiser'];
$r3 = 'beers';
$find=['/\b(?:'.implode('|',$p1).')\b/','/\b(?:'.implode('|',$p2).')\b/','/\b(?:'.implode('|',$p3).')\b/'];
$swap=[$r1,$r2,$r3];
var_export($find);
echo "\n";
var_export($swap);
echo "\n";
echo preg_replace($find,$swap,$string);

Output:

array (
  0 => '/\\b(?:sis|boom|bah)\\b/',                 // unescaped: /\b(?:sis|boom|bah)\b/
  1 => '/\\b(?:boo|hiss)\\b/',                     // unescaped: /\b(?:boo|hiss)\b/
  2 => '/\\b(?:guinness|heineken|budweiser)\\b/',  // unescaped: /\b(?:guinness|heineken|budweiser)\b/
)
array (
  0 => 'cheers',
  1 => 'jeers',
  2 => 'beers',
)
Rah rah, cheers cheers cheers, I read a book on beers

*Notes:

The word boundaries \b ensure that whole words are match, avoiding unintended mismatches.

If you need case-insensitivity, just use the i flag at the end of each regex pattern. e.g. /\b(?:sis|boom|bah)\b/i

Upvotes: 1

user10089632
user10089632

Reputation: 5570

$subject = 'sis + boo + guinness';
echo preg_replace(['/sis|boom|bah/','/boo|hiss/','/guinness|heineken|budweiser/'],['cheers','jeers','beers'],$subject);
// the result would be cheers + jeers + beers

replacement The string or an array with strings to replace. If this parameter is a string and the pattern parameter is an array, all patterns will be replaced by that string. If both pattern and replacement parameters are arrays, each pattern will be replaced by the replacement counterpart. If there are fewer elements in the replacement array than in the pattern array, any extra patterns will be replaced by an empty string. ...

If subject is an array, then the search and replace is performed on every entry of subject, and the return value is an array as well.

Upvotes: 0

Related Questions