1

I have a string that has numbers and math operators (+,x,-, /) mixed in it

'12+345x6/789'

I need to convert it into an array seperated by those math operators.

[12, +, 345, x, 6, /, 789]

What is a simple way of doing this?

Vincent Tang
  • 3,758
  • 6
  • 45
  • 63

3 Answers3

2

Splitting on consecutive non-digit chars \D+ you get

console.log ('12+345x6/789'.split (/\D+/))
// [ '12', '345', '6', '789' ]

If you add a capture group, (\D+) you get the separator too

console.log ('12+345x6/789'.split (/(\D+)/))
// [ "12", "+", "345", "x", "6", "/", "789" ]

If you want to support parsing decimals, change the regexp to /([^0-9.]+)/ - Note, \D used above is equivalent to [^0-9], so all we're doing here is adding . to the character class

console.log ('12+3.4x5'.split (/([^0-9.]+)/))
// [ "12", "+", "3.4", "x", "5" ]

And a possible way to write the rest of your program

const cont = x =>
  k => k (x)

const infix = f => x =>
  cont (f (x))

const apply = x => f =>
  cont (f (x))

const identity = x =>
  x

const empty =
  Symbol ()
  
const evaluate = ([ token = empty, ...rest], then = cont (identity)) => {
  if (token === empty) {
    return then
  }
  else {
    switch (token) {
      case "+":
        return evaluate (rest, then (infix (x => y => x + y)))
      case "x":
        return evaluate (rest, then (infix (x => y => x * y)))
      case "/":
        return evaluate (rest, then (infix (x => y => x / y >> 0)))
      default:
        return evaluate (rest, then (apply (Number (token))))
    }
  }
}

const parse = program =>
  program.split (/(\D+)/)
  
const exec = program =>
  evaluate (parse (program)) (console.log)

exec ('')             // 0
exec ('1')            // 1
exec ('1+2')          // 3
exec ('1+2+3')        // 6
exec ('1+2+3x4')      // 24
exec ('1+2+3x4/2')    // 12
exec ('12+345x6/789') // 2
Mulan
  • 129,518
  • 31
  • 228
  • 259
  • 2nd solution doesn't have seperators in it can you double check – Vincent Tang Mar 29 '18 at 01:07
  • 1
    @Kagerjay wups, I added the `()` in the explanation, but not in the source code. I fixed the 2nd snippet :D – Mulan Mar 29 '18 at 01:09
  • where exactly is the capture group on 2nd solution (aren't they normally `$1`,`$2`, etc)? Having trouble understanding this one – Vincent Tang Mar 29 '18 at 01:21
  • Okay I found its on MDN page https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/split. "If separator is a regular expression that contains capturing parentheses, then each time separator is matched, the results (including any undefined results) of the capturing parentheses are spliced into the output array. However, not all browsers support this capability." – Vincent Tang Mar 29 '18 at 01:32
  • 1
    @Kagerjay I included a way to write the rest of your program – Mulan Mar 29 '18 at 02:38
  • By the way I noticed something wrong with this solution. If you used `12+345x` as the input the output becomes`[12,+,345,""]` – Vincent Tang Apr 19 '18 at 02:06
  • @Kagerjay there’s no error handling for invalid programs like the example you shared – Mulan Apr 19 '18 at 02:34
2

If you are unconcerned with whitespace, all you need is

'12+345x6/78-9'.match(/\d+|[\+-\/x]/g);

which splits the string into numbers and the +, -, \, and x tokens.

'use strict';
const tokens = '12+345x6/78-9'.match(/\d+|[\+-\/x]/g);

console.log(tokens);

To handle whitespace, consider

'12+3 45 x6/78-9'.match(/\d|\d[\s\d]\d|[\+-\/x]/g);

which splits the string into numbers (optionally allowing whitespace as a digit separator within a single number) and +, -, \, and x.

'use strict';
const tokens = '12+3 45 x6/78-9'.match(/\d+\s?\d+|\d+|[\+-\/x]/g);


console.log(tokens);
Aluan Haddad
  • 29,886
  • 8
  • 72
  • 84
1

this is going to work

console.log('12+345x6/789'.match(/\D+|\d+/g))
xianshenglu
  • 4,943
  • 3
  • 17
  • 34