Search code examples
phpregexpreg-replacepreg-replace-callbacknegative-lookbehind

Replacing occurences of a specific word if not proceeded by another specific word?


I have some text like:

*open* blah blah blah blah blah *close* blah blah *open* blah blah *close* blah blah *close*

I was wondering how would I remove/replace any occurrences of *close* which are not proceeded by *open*.

So the above text would become:

*open* blah blah blah blah blah *close* blah blah *open* blah blah *close* blah blah

I though of maybe using regex with preg_replace - but my regex skills are not that strong?

<?php
$string = "*open* blah blah blah blah blah *close* blah blah *open* blah blah *close* blah blah *close*";

$string = preg_replace('#(?<!\*open\*)\*close\*#', '', $string); //this only works for immediate proceedings

echo($string);
?>

Code examples would be welcome.


Solution

  • It can be done without regex via the following code:

    $openTag = '*open*';
    $closeTag = '*close*';
    $openTagLength = mb_strlen($openTag);
    $closeTagLength = mb_strlen($closeTag);
    
    $subj = '*open* blah blah blah blah blah *close* blah blah *open* blah blah *close* blah blah *close*';
    $len = mb_strlen($subj);
    $isOpened = false;
    $res = '';
    for ($i = 0; $i < $len; )
    {
        if (mb_substr($subj, $i, $openTagLength) === $openTag) {
            // found open tag
            $res .= $openTag;
            $isOpened = true;
            $i += $openTagLength;
        } elseif (mb_substr($subj, $i, $closeTagLength) === $closeTag) {
            // found close tag
            if ($isOpened) {
                $res .= $closeTag;
            } // else skip
            $isOpened = false;
            $i += $closeTagLength;
        } else {
            // non-tag
            $res .= mb_substr($subj, $i, 1);
            $i++;
        }
    }
    echo $res;