I want to validate an input field with regular expression in JavaScript, which should validate the following cases:
Valid:
A and B and C and D
(A or B) and C
(A or B or C) and D
(A or B or C or D) and E
A and (B or C) and D
A and (B or C) or (C and D)
A or (B and C)
(A and B) or (C and D)
Invalid:
A and B and C and
(A or B and C
(A or B or C) and D or
(A or B or C or D and E
A and or (B or C) and D
A and (B or (C and D)))
A (B and C)
(A and B) or C and D)
(A and B or C and D)
Basically I need some letter from A-Z(only upper-case) followed by "and" or "or" and unlimited brackets, but the opening brackets amount should match the amount of closing ones. Also after an opening bracket I should have to be able to insert only A-Z upper-case and after a closing bracket "and", "or" or A-Z upper-case should also be valid. Nested brackets shouldn't also be valid.
I've came up with this solution, but it's only validating A-Z upper-case, "and" and "or" words and brackets, so all invalid cases provided are matching my regex.
/^[A-Z(]?[A-Z]| |and|or|[(]|[A-Z]|[)]/gm
CodePudding user response:
A JS regular expression could be:
^(?!\([^()]*\)$|.*([()])[^()]*(?=\1)|[^()]*[()](?:[^()]*[()][^()]*[()])*[^()]*$|.*\([A-Z]\))\(?[A-Z](?: (?:and|or) \(?[A-Z]\)?)*$
See an online demo
^
- Start-line anchor;(?!
- Open a negative lookahead with alternations;\([^()]*\)$
- Avoid a match with an operning paranthesis, 0 characters other than paranthesis, and a closing paranthesis. Or;.*([()])[^()]*(?=\1)
- 0 Character upto a opening/closing paranthesis in a 1st capture group followed by 0 characters other than paranthesis upto a backreference to 1st group. Or;[^()]*[()](?:[^()]*[()][^()]*[()])*[^()]*$
- A check for unbalanced paranthesis. The pattern will enfore there is a multiple of two paranthesis if any has been used. Or;.*\([A-Z]\)
- Test for 0 characters followed by opening, capital letter and direct closing, to avoid(A)
-like input;
\(?[A-Z]
- Match an optional paranthesis followed by A-Z (to allow a single letter to be a valid match too);(?: (?:and|or) \(?[A-Z]\)?)*
- Open a non-capture group to match a space, a nested non-capture group to match and|or followed by another space, an optional operning paranthesis, another capital letter and an optional closing paranthesis. This grouping is matches 0 times;$
- End-line anchor.
CodePudding user response:
Without nested brackets, this is easy. One disjunctive clause of the conjunctive normal form is
[A-Z]( or [A-Z])*
With parenthesis required around clauses using or
:
[A-Z]|\([A-Z]( or [A-Z])*\)
The whole formula would then be
([A-Z]|\([A-Z]( or [A-Z])*\))( and ([A-Z]|\([A-Z]( or [A-Z])*\)))*