Search code examples
phpregexpreg-match-allkeyword-searchword-boundary

PHP tag system with preg_match and foreach


I'm trying to build this tag system for my website, where it checks the written article (could be 400-1000 words), for specific words and make a string with all the keywords found, from the array.

The one I made is working alright, but there is some problems I would like to fix.

$a = "This is my article and it's about apples and pears. I like strawberries as well though.";

$targets = array('apple', 'apples','pear','pears','strawberry','strawberries','grape','grapes');
foreach($targets as $t)
{
   if (preg_match("/\b" . $t . "\b/i", $a)) {
    $b[] = $t;
   }
}
echo $b[0].",".$b[1].",".$b[2].",".$b[3];
$tags = $b[0].",".$b[1].",".$b[2].",".$b[3];

First of all, I would like to know, if there is any way, I can make this more effecient. I have a database with around 5.000 keywords and expanding day by day.

A you can see, I don't know how to get ALL the matches. I'm writing $b[0], $b[1] etc.

I would like it to just make a string with ALL the matches - but only 1 time per match. If apples is mentioned 5 times, then only 1 should go in the string.

A said - this works. But I don't feel, that this is the best solution.

EDIT:

I'm now trying this, but I cant get it to work at all.

$a = "This is my article and it's about apples and pears. I like strawberries as well though.";

$targets = array('apple', 'apples','pear','pears','strawberry','strawberries','grape','grapes');
$targets = implode('|', $targets);
$b = [];
preg_match("/\b(" . $targets . ")\b/i", $a, $b);

echo $b;

Solution

  • preg_match already saves the matches. So:

    int preg_match ( string $pattern , string $subject [, array &$matches [, int $flags = 0 [, int $offset = 0 ]]] )
    

    The 3 param is already saving the matches, change this:

    if (preg_match("/\b" . $t . "\b/i", $a)) {
        $b[] = $t;
    }
    

    To this:

    $matches = [];
    preg_match("/\b" . $t . "\b/i", $a, $matches);
    $b = array_merge($b, $matches);
    

    But, if you are comparing directly the word, the documentation recomends using strpos().

    Tip
    Do not use preg_match() if you only want to check if one string is contained in another string. Use strpos() instead as it will be faster.


    EDIT

    You could improve (in performance) your code if you still want to use preg_match by doing this, replace this:

    $targets = array('apple', 'apples','pear','pears','strawberry','strawberries','grape','grapes');
    foreach($targets as $t)
    {
       if (preg_match("/\b" . $t . "\b/i", $a)) {
        $b[] = $t;
       }
    }
    

    With this:

    $targets = array('apple', 'apples','pear','pears','strawberry','strawberries','grape','grapes');
    $targets = implode('|', $targets);
    
    preg_match("/\b(" . $t . ")\b/i", $a, $matches);
    

    Here you are joining all your $targets with | (pipe), so your regex is like this: (target1|target2|target3|targetN) so you do only one search and not that foreach.