0

I would like to write a regex to fulfil following requirements:

Test case Test string Is Valid
1 board add 0/1 aaa True
2 board add 0/1 xxx False
3 EMPTY_STRING True
4 True
5 board add 0/2 aaa True

Then, I decided to build the regex with python by make use of

(?(xxx)YES-PATTERN|NO-PATTERN)

I come up with following

  • (board add 0/1)?(?(1) (aaa|bbb))
    • If (board add 0/1) exists, we check whether it follows aaa or bbb
    • If (board add 0/1) does not exists, we make it pass

But, the regex above just does not work as expected. It failed on test case 2. Anyone know how to fix it?

You can check my regex by following url

https://regex101.com/r/M8UEsb/1

3
  • 1
    Just use 'xxx' not in string Commented Jun 9, 2022 at 17:29
  • No offence... I would like to code in regex. If not possible, I will write something else Commented Jun 9, 2022 at 17:40
  • You could also try ^(?!.*\bboard add 0/1 (?!aaa|bbb)).* Commented Jun 9, 2022 at 19:13

2 Answers 2

2

You are not matching the 2 in example nr. 5, only the 1.

But as the group 1 value is optional, and you only test for group 1 in the if/else clause, it can match at any position and the pattern is also unanchored.


You could also write an alternation that allows all the patterns instead of using if/else:

^[^\S\n]*(?:board add 0/[12] (?:aaa|bbb))?$

Explanation

  • ^ Start of string
  • [^\S\n]* Mach optional spaces without newlines
  • (?: Non capture group
    • board add 0/[12] Match the string ending on either 1 or 2
    • (?:aaa|bbb) Match one of the alternatives
  • )? Close the group
  • $ End of string

Regex demo

Example

import re

strings = ["board add 0/1 aaa", "board add 0/1 xxx", "", "    ", "board add 0/2 aaa"]

for s in strings:
    m = re.match(r"^[^\S\n]*(?:board add 0/[12] (?:aaa|bbb))?$", s)
    print(f"'{s}' ==> {bool(m)}")

Output

'board add 0/1 aaa' ==> True
'board add 0/1 xxx' ==> False
'' ==> True
'    ' ==> True
'board add 0/2 aaa' ==> True
Sign up to request clarification or add additional context in comments.

11 Comments

Why we need ^ & $ for this case?
@MondWan Only if you want to match the whole line. You can omit it if you want but then you can get partial matches. See regex101.com/r/xgmKKw/1
But without them, the regex does not pass test case 2
@MondWan The you can either make it ^\s*(?:board add 0/[12] (?:aaa|bbb|xxx)|\s*)$ regex101.com/r/NJXhwD/1 or more global ^\s*(?:board add 0/[12] [a-z]{3}|\s*)$ regex101.com/r/oHNSKC/1
They are still not passing test case 2.
|
1

This pattern checks the existence of aaa or bbb if the string starts with board add 0/1 or board add 0/2. And if any of board add 0/1 and board add 0/2 does not exist, it passes.

^(?:(?!board add 0/[12]).)*$|board add 0/[12] (?:aaa|bbb)

Regex Explanation

  • ^ Start of a string
  • (?: Non-capturing group
    • (?! Negative lookahead assertion - assert that the following regex does not match
      • board add 0/[12] Match board add 0/1 or board add 0/2
    • ) Close lookahead
    • . Any character except newline
  • ) Close non-capturing group
  • * The previous match can be matched zero or more times
  • $ End of a string
  • | OR. If the whole previous pattern did not match then check the next
  • board add 0/[12] Match board add 0/1 or board add 0/2
  • (?: Non-capturing group
    • aaa|bbb Match aaa or bbb
  • ) Close non-capturing group

See the demo

Python Example

import re

strings = [
    'board add 0/1 aaa',
    'board add 0/1 xxx',
    '',
    '                 ',
    'board add 0/2 aaa'
]

for string in strings:
    print(bool(re.match(r'^(?:(?!board add 0/[12]).)*$|board add 0/[12] (?:aaa|bbb)', string)))

Output

True
False
True
True
True

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.