[removed] Split a string by comma, except inside p

2020-02-07 05:21发布

问题:

Given string in the form:

'"abc",ab(),c(d(),e()),f(g(),zyx),h(123)'

How can I split it to get the below array format:

abc
ab()
c(d(),e())
f(g(),zyx)
h(123)

I have tried normal javascript split, however it doesn't work as desired. Trying Regular Expression but not yet successful.

回答1:

You can keep track of the parentheses, and add those expressions when the left and right parens equalize.

For example-

function splitNoParen(s){
    var left= 0, right= 0, A= [], 
    M= s.match(/([^()]+)|([()])/g), L= M.length, next, str= '';
    for(var i= 0; i<L; i++){
        next= M[i];
        if(next=== '(')++left;
        else if(next=== ')')++right;
        if(left!== 0){
            str+= next;
            if(left=== right){
                A[A.length-1]+=str;
                left= right= 0;
                str= '';
            }
        }
        else A=A.concat(next.match(/([^,]+)/g));
    }
    return A;
}

var s1= '"abc",ab(),c(d(),e()),f(g(),zyx),h(123)';
splitNoParen(s1).join('\n');

/*  returned value: (String)
"abc"
ab()
c(d(),e())
f(g(),zyx)
h(123)
*/


回答2:

This might be not the best or more refined solution, and also maybe won't fit every single possibility, but based on your example it works:

var data = '"abc",ab(),c(d(),e()),f(g(),zyx),h(123)';
// Create a preResult splitting the commas.
var preResult = data.replace(/"/g, '').split(',');
// Create an empty result.
var result = [];

for (var i = 0; i < preResult.length; i++) {
    // Check on every preResult if the number of parentheses match.
    // Opening ones...
    var opening = preResult[i].match(/\(/g) || 0;
    // Closing ones...
    var closing = preResult[i].match(/\)/g) || 0;

    if (opening != 0 &&
        closing != 0 &&
        opening.length != closing.length) {
        // If the current item contains a different number of opening
        // and closing parentheses, merge it with the next adding a 
        // comma in between.
        result.push(preResult[i] + ',' + preResult[i + 1]);
        i++;
    } else {
        // Leave it as it is.
        result.push(preResult[i]);
    }
}

Demo



回答3:

For future reference, here's another approach to top-level splitting, using string.replace as a control flow operator:

function psplit(s) {
  var depth = 0, seg = 0, rv = [];
  s.replace(/[^(),]*([)]*)([(]*)(,)?/g,
            function (m, cls, opn, com, off, s) {
    depth += opn.length - cls.length;
    var newseg = off + m.length;
    if (!depth && com) {
      rv.push(s.substring(seg, newseg - 1));
      seg = newseg;
    }
    return m;
  });
  rv.push(s.substring(seg));
  return rv;
}

console.log(psplit('abc,ab(),c(d(),e()),f(g(),zyx),h(123)'))

["abc", "ab()", "c(d(),e())", "f(g(),zyx)", "h(123)"]

Getting it to handle quotes as well would not be too complicated, but at some point you need to decide to use a real parser such as jison, and I suspect that would be the point. In any event, there's not enough detail in the question to know what the desired handling of double quotes is.



回答4:

You can't use .split for this, but instead you'll have to write a small parser like this:

function splitNoParen(s){
  let results = [];
  let next;
  let str = '';
  let left = 0, right = 0;

  function keepResult() {
    results.push(str);
    str = '';
  }

  for(var i = 0; i<s.length; i++) {
    switch(s[i]) {
    case ',': 
      if((left === right)) {
        keepResult();
        left = right = 0;
      } else {
        str += s[i];
      }
      break;
    case '(':
      left++;
      str += s[i];
      break;
    case ')':
      right++;
      str += s[i];
      break;
    default: 
      str += s[i];
    }
  }
  keepResult();
  return results;
}
  
var s1= '"abc",ab(),c(d(),e()),f(g(),zyx),h(123)';
console.log(splitNoParen(s1).join('\n'));

var s2='cats,(my-foo)-bar,baz';
console.log(splitNoParen(s2).join('\n'));



回答5:

Javascript

var str='"abc",ab(),c(d(),e()),f(g(),zyx),h(123)'
str.split('"').toString().split(',').filter(Boolean);

this should work