There are several approaches that you can take here, and I will list some of them.
Checking that for all cases, the requirement is always met
In this approach, we simply look for 0000(1111)?
and find all matches. Since ?
is greedy, it will match the 1111
if possible, so we simply check that each match is 00001111
. If it's only 0000
then we say that the input is not valid. If we didn't find any match that is only 0000
(perhaps because there's no match at all to begin with), then we say it's valid.
In pseudocode:
FUNCTION isValid(s:String) : boolean
FOR EVERY match /0000(1111)?/ FOUND ON s
IF match IS NOT "00001111" THEN
RETURN false
RETURN true
Checking that there is a case where the requirement isn't met (then oppose)
In this approach, we're using regex to try to find a violation instead, Thus, a successful match means we say the input is not valid. If there's no match, then there's no violation, so we say the input is valid (this is what is meant by "check-then-oppose").
In pseudocode
isValid := NOT (/violationPattern/ FOUND ON s)
Lookahead option
If your flavor supports it, negative lookahead is the most natural way to express this pattern. Simply look for 0000(?!1111)
.
No lookahead option
If your flavor doesn't support negative lookahead, you can still use this approach. Now the pattern becomes 00001{0,3}(0|$)
. That is, we try to match 0000
, followed by 1{0,3}
(that is, between 0-3 1
), followed by either 0
or the end of string anchor $
.
Fully spelled out option
This is equivalent to the previous option, but instead of using repetition and alternation syntax, you explicitly spell out what the violations are. They are
00000|000010|0000110|00001110|
0000$|00001$|000011$|0000111$
Checking that there ISN'T a case where the requirement isn't met
This relies on negative lookahead; it's simply taking the previous approach to the next level. Instead of:
isValid := NOT (/violationPattern/ FOUND ON s)
we can bring the NOT
into the regex using negative lookahead as follows:
isValid := (/^(?!.*violationPattern)/ FOUND ON s)
That is, anchoring ourself at the beginning of the string, we negatively assert that we can match .*violationPattern
. The .*
allows us to "search" for the violationPattern
as far ahead as necessary.
Attachments
Here are the patterns showcased on rubular:
- Approach 1: Matching only
0000
means invalid
- Approach 2: Match means invalid
- Approach 3: Match means valid
The input used is (annotated to show which ones are valid):
+ 00101011000011111111001111010
- 000011110000
- 0000110
+ 11110
- 00000
- 00001
- 000011
- 0000111
+ 00001111
References