-1

There is a file:

cat file.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

What I am trying to achieve: every word crocodile has to be replaced but has not to be replaces if between words dog (or mice) and crocodile there is word cat

Like so:

dog blah replacement blah dog blah cat blah crocodile blah dog blah replacement blah dog blah cat blah dog blah cat blah crocodile blah dog blah replacement blah mice blah cat blah crocodile

My progress:

$txt = preg_replace('/((dog|mice)(.*?)(?:(?!cat))(.*?))crocodile/', "$1replacement", $txt);

Every blah word means whatever.

  • It should replace by what blank space ?? – Sachin Yadav Oct 16 '19 at 19:04
  • 'crocodile' to 'replacement' but not if there is a word 'cat' between the words 'dog|mice' and the 'crocodile'. Dog ... cat...crocodile...dog...replacement. All in one line. To the end of line. – Dima Oct 16 '19 at 19:10
  • 's/danger/safety/' testfile.txt – Sachin Yadav Oct 16 '19 at 19:25
  • Consider that question is about php language – Dima Oct 16 '19 at 19:40
  • 1
    Here is a solution, regex101.com/r/hj12YN/1 but because this is a pure php question and has no relevance to Ubuntu I must vote to close as Blatantly Off-topic. This is a question more suitably asked at Stackoverflow. – mickmackusa Apr 10 at 0:58
0

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:

  1. start to consume when it encounters the word dog or mice then
  2. it will perform a lookahead with every step that the regex engine makes to ensure that the words dog, mice, and cat are not found while searching for the word crocodile then
  3. a space is expected before the word crocodile then
  4. 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
  5. a forward lookahead is used to check that the qualifying crocodile string is not followed by a cat string before being followed by dog or mice.

Pattern:

 /(?:dog|mice)(?:(?!dog|mice|cat).)* \Kcrocodile(?= (?:(?!dog|mice|cat).)* (?:dog|mice))/

Replacement:

Replacement

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.
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.