Search code examples
phpregexreplacepreg-replacewhitelist

Replace whitelisted substrings which are surrounded by specified characters with a corresponding value in user-supplied text


I'm trying to use preg_replace() to search for a string but only replace a portion of the string, rather than the entire string, in a dynamic fashion.

For example, I am able to find the strings od, :od, od:, #od, and od with my code below. I want to replace only the od portion with the word odometer and leave the colon, hashtag, and white spaces untouched. However, the way that my current preg_replace() is written would replace the colons and the hashtag in addition to the letters themselves. Any creative solutions to replace the characters only but preserve the surrounding symbols?

if(isset($_POST["text"]))
{
    $original = $_POST["text"];
    $abbreviation= array();
    $abbreviation[0] = 'od';
    $abbreviation[1] = 'rn';        
    $abbreviation[2] = 'ph';
    $abbreviation[3] = 'real';  
    $translated= array();
    $translated[0] ='odometer';
    $translated[1] ='run';
    $translated[2] ='pinhole';
    $translated[3] ='fake';

function add_regex_finders($str){
    return "/[\s:\#]" . $str . "[\s:]/i";
}

$original_parsed = array_map('add_regex_finders',$original);
preg_replace($original_parsed,$translated,$original);

}

Solution

  • You can add capture groups around the characters before and after the matched abbreviation, and then add the group references to the replacement string:

    function add_regex_finders($str){
        return "/([\s:\#])" . $str . "([\s:])/i";
    }
    
    $abbrevs_parsed = array_map('add_regex_finders', $abbreviation);
    $translt_parsed = array_map(function ($v) { return '$1' . $v . '$2'; }, $translated);
    echo preg_replace($abbrevs_parsed, $translt_parsed, $original);
    

    Demo on 3v4l.org

    Note you had a typo in your code, passing $original to the call to add_regex_finders when it should be $abbreviation.