Dara
Dara

Reputation: 13

php preg_match_all/preg_replace is truncating replacements for similar matches

I'm trying to mimic Twitter's hash tagging system, replacing all hashtags with clickable links. I put together a snippet that works but I discovered that if two words have similar beginnnings, the longer word only gets replaced (by a clickable link) to the length where the shorter word stopped. ie, if I have a sentence '#tool in a #toolbox', #tool becomes a link, and only #tool in #toolbox becomes a link, not the entire #toolbox.

Below is the snippet:

<?php


//define text to use in preg_match and preg_replace 
$text = '#tool in a #toolbox';

//get all words with hashtags
preg_match_all("/#\w+/",$text,$words_with_tags);

    //if there are words with hash tags
    if(!empty($words_with_tags[0])){

        $words = $words_with_tags[0];

        //define replacements for each tagged word, 
        //   $replacement     is an array of replacements for each word
        //   $words            is an array of words to be replaced
        for($i = 0; $i < sizeof($words) ; $i++ ){

            $replacements[$i] = '<a href="'.trim($words[$i],'#').'">'.$words[$i].'</a>';

            // format word as /word/ to be used in preg_replace 
            $words[$i] = '/'.$words[$i].'/';
        }

        //return tagged text with old words replaced by clickable links
        $tagged_text = preg_replace($words,$replacements,$text);

    }else{
        //there are no words with tags, assign original text value to $tagged_text
        $tagged_text = $text;
    }


echo $tagged_text;


?>

Upvotes: 1

Views: 213

Answers (2)

Jonny 5
Jonny 5

Reputation: 12389

What about capturing and doing a simple preg_replace()

$tagged_text = preg_replace('~#(\w+)~', '<a href="\1">\0</a>', $text);

Test at eval.in outputs to:

<a href="tool">#tool</a> in a <a href="toolbox">#toolbox</a>

Test at regex101

Upvotes: 1

ʰᵈˑ
ʰᵈˑ

Reputation: 11365

You can use preg_replace_callback

<?php

$string = "#tool in a #toolbox";

 $str = preg_replace_callback(
            '/\#[a-z0-9]+/',
            function ($matches) {
                return "<a href=\"". ltrim($matches[0], "#") ."\">". $matches[0] ."</a>";
            }, $string);
    echo $str;
    //Output: <a href="tool">#tool</a> in a <a href="toolbox">#toolbox</a>

https://eval.in/198848

Upvotes: 0

Related Questions