javascriptphpregex

Optional (opening) parenthesis but closing parenthesis should then be mandatory


I've created a regular expression which allows users to make formulas in my application. The regular expression I have works fine, however I want users to make opening and closing parenthesis.

My current regular expression is:

(
    ^[(N|R)]:   //START WITH N: OR R:

    (?:
        (?:
            [-.0-9]+|BT|PT|PN|PR  //ALLOW 48.934, BT, PT, PN OR PR
        )
        (?:
            \+|\*|\-|\/ //ALLOW OPERATORS /,*,+ and -
        )
    )+ //REPEAT x TIMES

    (?:
        [-.0-9]+|BT|PT|PN|PR //MUST END WITH 48.934, BT, PT, PN OR PR
    )
    
    (?:
        :V //ADD MANDATORY :V
    )

    (?:
        [-.0-9]+ //CLOSE REGEX WITH NUMBER
    )
)

A few examples in which the regular expression currently works:

N:0.3*BT/PN*PR:V1
N:2000+PN/BT:V0.5
R:BT*PN-500:V2

I'd like the regular expression to work with () which it currently doesn't for a few examples:

N:(2000+PN)/BT:V0.5
R:BT*(PN-500):V2

I've read about positive and negative lookahead, to create if / else structures but I can't seem to find the right logic for my needs.

Much appreciated if someone can guide me in the right direction.

P.S. I'm using the JavaScript regex engine.


Solution

  • Here is a modified version of your regex that allows for any number of matched (but not nested) parens (see on regex101):

    (?=
        [^()]*
        (\([^()]+\)[^()]*)*
        $
    )
    
    ^[NR]:   //START WITH N: OR R:
    
    (?:
        \(?(?:[-.0-9]+|BT|PT|PN|PR)\)? //ALLOW 48.934, BT, PT, PN OR PR
        [-+*\/]                        //ALLOW OPERATORS /,*,+ and -
        \(?(?:[-.0-9]+|BT|PT|PN|PR)\)? //ALLOW 48.934, BT, PT, PN OR PR
    )+ //REPEAT x TIMES
    
    (?:
        [-+*\/]                        //ALLOW OPERATORS /,*,+ and -
        (?:[-.0-9]+|BT|PT|PN|PR)       //ALLOW 48.934, BT, PT, PN OR PR
        \)?
    )*`
    
    
    :V //ADD MANDATORY :V
    [-.0-9]+ //CLOSE REGEX WITH NUMBER
    

    Explanation:

    Other than some clean-up of [(N|R)] and other extraneous groupings, the main change is to add a positive lookahead at the very beginning to ensure that any parens are found in pairs:

    (?=
        [^()]*
        (\([^()]+\)[^()]*)*
        $
    )
    

    Then parens are allowed around each number or variable.