1

I need PCRE2 regex to find all occurences of "no" as well as first and last occurences of "yes".

Expected results:

"no/yes" - expect two matches: "no" and "yes"
"no/yes/word/yes/no" - expect four matches: "no", "yes", "yes", "no"
"yes/yes/no/word/yes" - expect three matches: first "yes", "no", third "yes"
"yes/no/yes/yes" - expect three matches: first "yes", "no", third "yes"

I try this regex but it don't work as expected with "yes/no/yes/yes".

This subtask can make me happy with main goal.

klee
  • 55
  • 6
  • @Poul Bak, I try this regex. Unfortunately it compiles with error "A quantifier inside a lookbehind makes it non-fixed width". I ask Michail to check this. He confirm that he have this error too. – klee Oct 08 '22 at 20:19
  • Different matches can be replaced with different values as Michail show in prev topic https://stackoverflow.com/questions/73930041/one-regex-to-replace-some-different-things – klee Oct 08 '22 at 20:21

2 Answers2

2

You can achieve your desired result, if you can use PCRE2 replacement string conditionals. You can use this regex (whitespace added for clarity, either use the x flag or delete the newlines between alternations):

(no)|
(yes)(?!.*yes)|
((?!(?=(?<a>[\s\S]*))(?<b>yes.*(?=\k<a>\z)|(?<=(?=x^|(?&b))[\s\S])))yes)

It matches one of:

  • (no) : no (captured in group 1)
  • (yes)(?!.*yes) : yes not followed by yes (captured in group 2)
  • ((?!(?=(?<a>[\s\S]*))(?<b>yes.*(?=\k<a>\z)|(?<=(?=x^|(?&b))[\s\S])))yes) : this is the equivalent of a variable length negative lookbehind for (?<!yes.*)(yes) with the yes captured in group 3. For the derivation of this part of the regex, see this blog post.

You can then use conditional replacements, replacing group 1 with - and groups 2 and 3 with +

${1:+-:+}

For input of

no/yes
no/yes/yes/no
/yes/yes/no/yes
no/word/no/yes/yes/yes/no
yes/no
yes/no/yes/word/yes
/word/yes/no/no/no/yes/yes
yes/no/yes/yes

This gives:

-/+
-/+/+/-
/+/yes/-/+
-/word/-/+/yes/+/-
+/-
+/-/yes/word/+
/word/+/-/-/-/yes/+
+/-/yes/+

Demo on regex101

Nick
  • 138,499
  • 22
  • 57
  • 95
  • Wow!! Your answer is divine. It doing exactly what I want. Thank you very much! – klee Oct 09 '22 at 08:11
  • 1
    @Nick, your answer is really great +! I know performance is not Klee's concern. However it seems ``(no)|yes(?!.*yes)|((?<!yes|(?!(?2)).))yes`` may also be used with the same idea https://regex101.com/r/C7TSHp/1 – Michail Oct 09 '22 at 08:31
  • Thank a lot, Michail. This one works too. – klee Oct 09 '22 at 09:21
  • @Michail that is brilliant - much simpler! you really should post that as an answer. I should have removed my capture groups 2 & 3, I was originally matching everything and so needed them, but the final one does not. – Nick Oct 09 '22 at 11:40
  • @klee I'm glad I could help - but if Michail posts his comment as an answer you should definitely accept that instead. – Nick Oct 09 '22 at 11:41
0

You are overthinking it.
There is no real point in using ONE regex to replace them all.
Just use multiple regexes.


s.replace(/yes/, '+').replace(/yes(?!.*yes)/, '+').replaceAll(/no/g, '-')

Also, there's no real way to replace one entry exept replacing it

Dimava
  • 7,654
  • 1
  • 9
  • 24
  • Thank you. But the private application I use does not give me access to the programming language. I only have access to the input of ONE regular expression with which I can process the text. To perform several tasks, I have to complicate this regular expression – klee Oct 08 '22 at 17:04