简体   繁体   English

Javascript:用逗号分隔字符串,括号内除外

[英]Javascript: Split a string by comma, except inside parentheses

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.我已经尝试过正常的 javascript 拆分,但是它没有按预期工作。 Trying Regular Expression but not yet successful.尝试正则表达式但尚未成功。

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)
*/

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演示

For future reference, here's another approach to top-level splitting, using string.replace as a control flow operator:为了将来参考,这是另一种顶级拆分方法,使用string.replace作为控制流运算符:

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.让它处理引号也不会太复杂,但在某些时候你需要决定使用真正的解析器,比如jison ,我怀疑这就是重点。 In any event, there's not enough detail in the question to know what the desired handling of double quotes is.无论如何,问题中没有足够的细节来了解所需的双引号处理是什么。

You can't use .split for this, but instead you'll have to write a small parser like this:您不能为此使用.split ,而是必须编写一个像这样的小型解析器:

 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'));

Had a similar issue and existing solutions were hard to generalize.有类似的问题,现有的解决方案很难概括。 So here's another parser that's a bit more readable and easier to extend to your personal needs.因此,这是另一个更具可读性且更易于扩展到您的个人需求的解析器。 It'll also work with curly braces, brackets, normal braces, and strings of any type.它也适用于大括号、方括号、普通大括号和任何类型的字符串。 License is MIT.许可证是麻省理工学院。

export function parse_arguments(input:string, split_by = ",")
{
    // Some symbols can be nested, like braces, and must be counted
    const state = {"{":0,"[":0,"(":0};
    // Some cannot be nested, and just flip a flag
    const state_singlo = {"\"":false,"'":false,"\`":false}

    // Nestable symbols come in sets, usually in pairs.
    // These sets increase or decrease the state, depending on the symbol.
    const pairs : Record<string,[keyof typeof state,number]> = {
        "{":["{",1],
        "}":["{",-1],
        "[":["[",1],
        "]":["[",-1],
        "(":["(",1],
        ")":["(",-1]
    }

    let start = 0;
    let results = [];
    let length = input.length;
    for(let i = 0; i < length; ++i)
    {
        let char = input[i];

        // Backslash escapes the next character. We directly skip 2 characters by incrementing i one extra time.
        if(char === "\\")
        {
            i++;
            continue;
        }
        // If it's a paired symbol, increase or decrease the state based on our "pairs" constant.
        if(char in pairs)
        {
            let [key,value] = pairs[char];
            state[key] += value;
        }
        // If the symbol exists in the single/not nested state object, flip the corresponding state flag.
        else if(char in state_singlo)
        {
            state_singlo[char as keyof typeof state_singlo] = !state_singlo[char as keyof typeof state_singlo];
        }
        // If it's our split symbol, push the 
        else if(char === split_by)
        {
            if(Object.entries(state).every(([k,v])=>v == 0) && Object.entries(state_singlo).every(([k,v])=>!v))
            {
                results.push(input.substring(start,i))
                start = i+1;
            }
        }
    }

    // Add the last segment if the string didn't end in the split_by symbol, otherwise add an empty string
    if(start < input.length)
        results.push(input.substring(start,input.length))
    else
        results.push("");

    return results;
}

With this regex, it makes the job:使用此正则表达式,它可以完成工作:

 const regex = /,(?;[^(]*\))/g, const str = '"abc",ab(),c(d(),e()),f(g(),zyx);h(123)'. const result = str;split(regex). console;log(result);

Javascript Javascript

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

this should work这应该工作

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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