简体   繁体   中英

Unary operator split using regex

There is a lot of related regex questions but none of them solves my problem, since I don't have parenthesis in my expressions.

I have a string mathematical expression for example: 1*2+3-99/50

I need to tokenize the expression to convert the expression to post-fix notation. So I used split with regex as follows:

'1*2+3-99/50'.split(/([+\-*/])/)                   // operands have no unary (-)
// ['1', '*', '2', '+', '3', '-', '99', '/', '50'] 

That works fine. But working with unary operators, it doesn't work. So I tried to use lookahead to detect if a minus comes after another operator:

'1*-2+-3--99/-50'.split(/([+\-*/])(?=-)/               // all operands have unary (-)
// ['1', '*', '-2', '+', '-3', '-', '-99', '/', '-50']

This also works but only because all numbers already have negative sign.

I have tried to capture first the operands with unary (-) operators to append it to the final tokens, but I lost order which is important in the evaluating phase. Also tried to read about conditional regex, but doesn't make much of a sense in my case.

Is it possible to split tokens containing negative signs on one single split?

Try splitting with \\b

 var a = '1*-2+-3-99/-50'.split(/(\\b[-+*/])/); console.log(JSON.stringify(a))

First, you really don't want to do this with regular expressions. Importantly, you need to keep track of the order of operations, something that postfix can take for granted but infix cannot.

This sample code uses regular expressions, but that's not where the real logic resides:

 function toPostfix(equation) { let output = ""; let additions = equation.replace(/\\b\\s*-/g, "+-").split(/\\+/); if (additions.length > 1) { output = "+)"; for (let a = additions.length - 1; a >= 0; a--) { output = toPostfix(additions[a]) + " " + output; } return "( " + output; } else { if (equation.match(/^1\\/-?[0-9]+$/)) { return "( 1 " + equation.substring(2) + " /)"; } let multiplications = equation.replace(/\\//g, "*1/").split(/\\*/); if (multiplications.length > 1) { output = "*)"; for (let m = multiplications.length - 1; m >= 0; m--) { output = toPostfix(multiplications[m]) + " " + output; } return "( " + output; } else { return equation; } } } console.log(toPostfix('1*2+3-99/50')); // "( ( 1 2 *) 3 ( -99 ( 1 50 /) *) +)"

For simplicity, this converts subtractions to additions of negative numbers and divisions to multiplications of inverted ( 1/n ) numbers. To observe order of operations, we have to split by the additions/subtractions first, then break down to each multiplication/division. I used a recursive call to break down each piece and build up the answer incrementally, right to left.

This only accounts for + - * and / . No parentheses, no exponents.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM