JavaScript RegExp: match all specific chars ignoring nested parentheses

Viewed 249

Actually I need to split this line by whitespaces ignoring those in parentheses (could be nested):

var string = 'a b c(a b c) d(a (b) c)'

Into this array:

['a', 'b', 'c(a b c)', 'd(a (b) c)']

The essence of my task is to get list of all variables and function calls separated by whitespaces

So, splitting by whitespaces, everything in parentheses should be ignored

I understand how it is godless to ask such questions, but I am totally dumb when it comes to regexps and, if that, ready to wait to start a bounty) Thx)

Maybe it should be something like this:

string = 'a b c(a b c) d(a (b) c)'.relaceWhitespacesinParentheses('&wh;')

// 'a b c(a&wh;b&wh;c) d(a&wh;(b)&wh;c)'

string.split(' ')

// ['a', 'b', 'c(a&wh;b&wh;c)', 'd(a&wh;(b)&wh;c)']

Everything next is obvious

3 Answers

var str = 'a b d(a (b) c) c(a b c)   e(a (f t(o a i) ) ) ';
str = str.trim();
var result = [];
var open_bracket = 0;
var curr_str = '';

for (var i = 0; i < str.length; ++i) {
  if (str.charAt(i) === '(') open_bracket++;
  if (str.charAt(i) === ')') open_bracket--;

  if (str.charAt(i) == ' ') {
    if (open_bracket == 0 && curr_str != '') {
      result.push(curr_str);
      curr_str = '';
    } else if (open_bracket > 0) {
      curr_str += str.charAt(i);
    }
  } else {
    curr_str += str.charAt(i);
  }
}

result.push(curr_str); // to include the last matched token.
console.log(result);

We move inside the string character by character. When we find a space, we see if we need to accommodate it in out result by checking if we have any brackets open. If yes, we append it to our temp result curr_str, else, we add the current curr_str to our results.

Maybe something like this? There's probably a tidier way

var string = 'a b c(a b c) d(a (b (a b c) d) c)'
var split = string.split(' ')

var numberOfBrackets = 0
var elements = []
split.reduce(function (acc, cur) {
  if (cur.includes('(')) {numberOfBrackets++}
  if (cur.includes(')')) {numberOfBrackets--}
  if (numberOfBrackets !== 0) {
    return acc + ' ' + cur
  } else {
    elements.push((acc + ' ' + cur).trim())
  }
  return ''
}, '')

console.log(elements)

If there is max one level of nesting you could try this pattern.

var str = 'a b c(a b c) d(a (b) c)';

var res = str.match(/\w+\([^)(]*(?:\([^)(]*\)[^)(]*)*\)|\S+/g);

console.log(res);

You'd need to add each level of deeper nesting to the pattern. Eg with max two levels (fyi).

Related