Search code examples
regexpcrepcre2

Match first and last "yes" as well as all "no"


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.


Solution

  • 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