0

I have an array of words which I am using to highlight words in a string, some of the words however might appear as part of a phrase, and so I would like the phrase to take precedence over the single word in the highlight:

For example:

$seo = ['apple', 'apple tree', 'orchard'];

$description = "In my orchard I have a large Apple Tree";

Desired effect:

In my <strong>orchard</strong> I have a large <strong>Apple Tree</strong>

In my own first attempt, I looped through the array running preg_replace() against the string, but I am getting nested highlights like this <strong><strong>Apple</strong> Tree</strong>.

2 Answers 2

1

First, you shouldn't use a loop to replace each word individually, but a regex alternatives list (foo|bar|thingy).

  $rx_words = implode("|", array_map("preg_quote", $words));
  $text = preg_replace("/\b($rx_words)\b/i", 

(Actually that preg_quote misses the second param, but as long as you don't have forward slashes in the keywords, it'll work.)

Then you can also make it safer with an assertion:

  $text = preg_replace("/(?<!<strong>)\b($rx_words)\b/i",

So it will ignore words that are already wrapped. That's just a workaround, but quite often sufficient.

Sign up to request clarification or add additional context in comments.

13 Comments

See also php regex to match outside of html tags for the followup problem.
Can you expand on your answer? I have no idea on how to implement it, and it seems incomplete to my application? $seo=array(); $description="In my orchard I have a large Apple Tree";
Replace your foreach with the two lines above. Obviously the preg_replace still needs the two params you already have in that function.
Works quite well when I test it. Maybe you should show what you've actually tried?
preg_replace() expects at least 3 parameters, 2 given
|
0

Sort your array of replaceable words by length descending before calling preg_replace(). This will ensure that longer strings are matched before shorter words and therefore avoid the nested replacement problem that you were encountering.

Code: (Demo)

$seo = ['apple', 'apple tree', 'orchard'];
$description = "In my orchard I have a large Apple Tree";

array_multisort(array_map('strlen', $seo), SORT_DESC, $seo);

var_export(
    preg_replace(
        '#\b(?:' . implode('|', $seo) . ')\b#i',
        '<strong>$0</strong>',
        $description
    )
);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.