1

I'm trying to render a react input element that can either take in a number or a string with BODMAS operations like (5*3)+8 and evaluate it. I would like to first valid the BODMAS string so I'm trying to come up with a regular expression that validates that the string is valid, for example it catches something with a missing parentheses like (5*3 +8

I have two expressions so far

  const regex = /^(?:\s*\d+(?:\s*[+*/-]\s*\d+)*\s*)$/;

This one wont validate something like (5+30)*8 while the other

const regex2 = /^\(*(\d+(\.\d+)*|\((\d+(\.\d+)*|\(*(\d+(\.\d+)*|\((\d+(\.\d+)*|[\+-\/\*]))*\)*)*\)*)*[\+-\/\*]*)+\)*$/

This one returns as invalid. I'm new to regex and I think there's something I may be missing.

Wiktor Stribiżew
  • 607,720
  • 39
  • 448
  • 563
ayesigwar
  • 11
  • 2
  • 1
    To the best of my knowledge, a regex will not be enough to properly parse/validate a parenthesized expression. You'll need an actual parser. – AKX Dec 15 '22 at 08:01
  • The two are different in many respects. The first does not accept decimal numbers. The second doesn't allow spacing. etc, etc. They seem to come from different unrelated sources... and you copied them without really understanding what they are. – trincot Dec 15 '22 at 08:01

1 Answers1

1

The best way would be to use a parser.

But if you prefer, you could iteratively simplify the input string until no more parentheses can be removed.

Below snippet is an implementation of that. The user's input is validated in real time:

function validate(expr) {
    expr = expr.replace(/\d+(\.\d+)?/g, "0")    // Simplify numbers to "0"
               .replace(/\s+/g, "")             // Remove white space
               .replace(/\B[+-]+(?=[0(])/g, "") // Remove unary operators (minus and plus)
               .replace(/[+*\/^-]/g, "-");      // Simplify binary operators to "-"
    for (let i = expr.length + 1; i > expr.length; ) {
        i = expr.length;
        expr = expr.replace(/\(0(-0)*\)/g, "0"); // Remove inner parentheses
    }
    return /^0(-0)*$/.test(expr);
}

// I/O management

const input = document.querySelector("input");
const refresh = () => input.className = validate(input.value) ? "ok" : "error";
input.oninput = refresh;
refresh();
.error { background: orange }
.ok { background: lightgreen }
Expression: <input type="text">

For parsing an expression, use the Shunting yard algorithm, possibly with some extensions to support functions and more. See for instance my implementation here.

trincot
  • 317,000
  • 35
  • 244
  • 286
  • 1
    Thank you very much. I have decided to use a parser but this answer has provided a good learning opportunity – ayesigwar Dec 15 '22 at 13:57