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])*\)))*
