After receiving feedback on Meta, this question (to my surprise) is on-topic so I'll explain one working technique.
I find your plain English explanation of the pattern requirements to be a little fuzzy, so I need to clarify that my pattern will:
- start to consume when it encounters the word
- it will perform a lookahead with every step that the regex engine makes to ensure that the words
cat are not found while searching for the word
- a space is expected before the word
- the metacharacter
\K is used to "release" all previously consumed characters -- doing so allows only the word
crocodile to be used as the fullstring match -- which will be replaced ...but the validation is not finished yet... then
- a forward lookahead is used to check that the qualifying
crocodile string is not followed by a
cat string before being followed by
/(?:dog|mice)(?:(?!dog|mice|cat).)* \Kcrocodile(?= (?:(?!dog|mice|cat).)* (?:dog|mice))/
PHP Code: (Demo)
$txt = 'dog blah crocodile blah dog blah cat blah crocodile blah dog blah crocodile blah dog blah cat blah dog blah cat blah crocodile blah dog blah crocodile blah mice blah cat blah crocodile';
echo preg_replace('/(?:dog|mice)(?:(?!dog|mice|cat).)* \Kcrocodile(?= (?:(?!dog|mice|cat).)* (?:dog|mice))/', 'replacement', $txt);
// output is identical to what is expected in your question.
I am not including any word boundary metacharacters because it is hard for me to guess from your fabricated input string if this is necessary. There is a probability that the inclusion of
\b's in the pattern will improve accuracy.
p.s. some syntax notes...
(?: ... ) is a non-capturing group
(?! ... ) is a negative lookahead.
(?= ... ) is a positive lookahead.