I'm looking for all instances of a certain character in a string of text except for when it is both prefixed and suffixed a certain way.
A simple example of this would be to find all instances of "a" in the string "I am a cat in a hat in a car" except where it appears in the word "cat":
I am acatin a hat in a car
Combining a negative lookbehind assertion and a negative lookahead assertion doesn't seem to work because it fails when either of the assertions are triggered rather than only when both are triggered.
Using a regex to find "a"s but ignore "ca"s ignores the word "car":
/(?<!c)a/g
I am acatin a hat in acar❌
Using a regex to find "a"s but ignore "at"s ignores the word "hat":
/a(?!t)/g
I am acatin ahat❌ in a car
Combining the two ignores both "car" and "hat":
/(?<!c)a(?!t)/g
I am acatin ahat❌ in acar❌
Regex seems to NOR the two assertions, is it possible to NAND them?
CodePudding user response:
You can nest the lookarounds, matching a and assert that to the left is not ca
that is followed by t
and use word boundaries \b
to prevent a partial word match.
a(?<!\bca(?=t\b))
Or written with the lookbehind first, asserting not c
to the left:
(?<!\bc(?=at\b))a
CodePudding user response:
You can use the exception token [^...]
and alternate between both positive lookarounds: /(?<=[^c])a|a(?=[^r])/g
.
By setting two exceptions in an OR, it's like a NAND gate and 2 NOT gates:
They both have to be true in order for it to be no match 1 and 1 => 0
Only one exception needs to be false so there is a match 0 and 1 => 1
If both are false then there's a match as well 0 and 0 => 1
Segment | Meaning |
---|---|
(?<=[^c])a |
Match literal "a" if there is anything BUT a literal "c" before it |
| |
OR |
a(?=[^r]) |
Match literal "a" if there is anything BUT a literal "r" after it |