André Ferraz
André Ferraz

Reputation: 1521

preg_replace with a word in an array

I am trying to use certain words in a array called keywords, which will be used to be replaced in a string by "as".

for($i = 0; $i<sizeof($this->keywords[$this->lang]); $i++)
    {
        $word = $this->keywords[$this->lang][$i];
        $a = preg_replace("/\b$word\b/i", "as",$this->code);
    }

It works with if I replace the variable $word with something like /\bhello\b/i, which then would replace all hello words with "as".

Is the approach am using even possible?

Upvotes: 0

Views: 437

Answers (2)

Casimir et Hippolyte
Casimir et Hippolyte

Reputation: 89547

Before to be a pattern, it's a double quoted string, so variables will be replaced, it's not the problem.

The problem is that you use a loop to change several words and you store the result in $a:

  • the first iteration, all the occurences of the first word in $this->code are replaced and the new string is stored in $a.
  • but the next iteration doesn't reuse $a as third parameter to replace the next word, but always the original string $this->code

Result: after the for loop $a contains the original string but with only the occurences of the last word replaced with as.

When you want to replace several words with the same string, a way consists to build an alternation: word1|word2|word3.... It can easily be done with implode:

$alternation = implode('|', $this->keywords[$this->lang]);

$pattern = '~\b(?:' . $alternation . ')\b~i';

$result = preg_replace($pattern, 'as', $this->code);

So, when you do that, the string is parsed only once and all the words are replaced in one shot.


If you have a lot of words and a very long string:

Testing a long alternation has a significant cost. Even if the pattern starts with \b that highly reduces the possible positions for a match, your pattern will have hard time to succeed and more to fail.

Only in this particular case, you can use this another way:

First you define a placeholder (a character or a small string that can't be in your string, lets say §) that will be inserted in each positions of word boundaries.

$temp = preg_replace('~\b~', '§', $this->code);

Then you change all the keywords like this §word1§, §word2§ ... and you build an associative array where all values are the replacement string:

$trans = [];
foreach ($this->keywords[$this->lang] as $word) {
    $trans['§' . $word . '§'] = 'as';
}

Once you have do that you add an empty string with the placeholder as key. You can now use the fast strtr function to perform the replacement:

$trans['§'] = '';
$result = strtr($temp, $trans);

The only limitation of this technic is that it is case-sensitive.

Upvotes: 1

Vishal Wadhawan
Vishal Wadhawan

Reputation: 1085

it will work if you keep it like bellow:

$a = preg_replace("/\b".$word."\b/i", "as",$this->code);

Upvotes: 0

Related Questions