如何基于逗号分割字符串,但括号内除外

时间:2015-10-14 23:57:46

标签: javascript regex string

我有一个包含创建查询的字符串,我试图根据逗号分割它。不幸的是,有些行中有逗号括号括起来。

示例:

dbo.Display_Test1.Column,
CASE WHEN CHARINDEX(' To ', Test3) > 0 AND CHARINDEX('XVR', Test3)  = 0 THEN LEFT(Test3, (CHARINDEX(' To ', Test3) - 12)) ELSE Test3 END AS Test3,
dbo.Display_Test2.Column,
ISNULL((CASE WHEN [2-Display-Test4].[Total Number] > 0 AND  [1-Display-Test5].SumOfNumber = 0 THEN 0 ELSE (([2-Display-Test4].[Total Number] * 1000) / [1-Display-Test5].SumOfNumber)  END), 0) AS Test6,

我想根据不在(可能是多个)括号内的逗号分割我的字符串。作为参考,我的例子应该分为换行符(尽管我的字符串中没有换行符)。

我尝试了许多不同的解决方案,但都没有做得很好:

/(?:\(*[^()]*\)|[^,])+/g适用于第1,3和4行,但在第2行失败。它将该行分成多个匹配。

/((?:[^,(]+|(\((?:[^()]+)|$1\)))+)/g适用于第1,2和3行,但在第4行失败。它还将该行分为多个匹配。

我似乎无法使其发挥作用。任何帮助表示赞赏。

3 个答案:

答案 0 :(得分:2)

可能的一种解决方案:(注意:我们删除了分离彗星)



var str = "dbo.Display_Test1.Column, CASE WHEN CHARINDEX(' To ', Test3) > 0 AND CHARINDEX('XVR', Test3)  = 0 THEN LEFT(Test3, (CHARINDEX(' To ', Test3) - 12)) ELSE Test3 END AS Test3, dbo.Display_Test2.Column, ISNULL((CASE WHEN [2-Display-Test4].[Total Number] > 0 AND  [1-Display-Test5].SumOfNumber = 0 THEN 0 ELSE (([2-Display-Test4].[Total Number] * 1000) / [1-Display-Test5].SumOfNumber)  END), 0) AS Test6,";
// if the string don't end by a coma , we add it.
var strArr = str.replace(/,*\s*$/ , ',').split('');

var res;
res = strArr.reduce(function( trans , charValue ){ 

  if(charValue === '(') {
     trans.deep++;
  }
  
  if(charValue === ')') {
     trans.deep--;
  }
  
  if( trans.deep === 0){
    if(charValue===',') {
       trans.arr.push( trans.str);
       trans.str = '';
    }else{
       trans.str += charValue;
    }
    
  }else{
       trans.str += charValue;
    }
  return  trans;
  
}, { arr : [] , str : '' ,deep : 0});

document.write('<pre>' + JSON.stringify(res.arr , null , ' ') + '</pre>');
&#13;
&#13;
&#13;

编辑

  • 根据评论中 Thriggle 的建议,我添加了字符串不以逗号结束的情况。
  • 更改了变量名称。

答案 1 :(得分:0)

当然,如果我们想要无限制地嵌套括号,那么就不可能避免循环。对于某些有界嵌套,我们可以写一个捕获它的正则表达式。

最多1个括号级别可以是

/((?:[^(),]|\([^()]*\))+)/g

最多2个括号级别(可能是你的情况)

/((?:[^(),]|\((?:[^()]|\([^()]*\))*\))+)/g

依此类推,用[^()]*

代替(?:[^()]|\([^()]*\))*

答案 2 :(得分:0)

正则表达不会让你到达你想要的地方,仍然允许随意的复杂性。

一种方法是遍历字符串中的每个字符,跟踪打开和关闭括号的时间,并且只有当打开和关闭括号的数字相互抵消时才会在逗号上拆分(所以你知道你&#39 ;不在括号内。)

function splitQuery(input){
  var arr = [];
  var lastStart = 0;
  var open = 0;
  for(var i = 0, len = input.length; i < len; i++){
    var curr = input[i];
    if(curr === "("){open += 1;}
    else if(curr === ")"){ open = open < 1 ? 0 :open -=1;}
    else if(curr === ","){
      if(open === 0){
        arr.push(input.substring(lastStart,i));
        lastStart = i+1;
      }
    }else if(i+1 === len){
       arr.push(input.substring(lastStart,i+1));
    }
  }
  return arr;
}

请注意,在处理特别大的字符串时,这种方法可能很昂贵(从性能角度来看)。

这是一个有效的例子:

&#13;
&#13;
var query = "dbo.Display_Test1.Column, CASE WHEN CHARINDEX(' To ', Test3) > 0 AND CHARINDEX('XVR', Test3)  = 0 THEN LEFT(Test3, (CHARINDEX(' To ', Test3) - 12)) ELSE Test3 END AS Test3, dbo.Display_Test2.Column, ISNULL((CASE WHEN [2-Display-Test4].[Total Number] > 0 AND  [1-Display-Test5].SumOfNumber = 0 THEN 0 ELSE (([2-Display-Test4].[Total Number] * 1000) / [1-Display-Test5].SumOfNumber)  END), 0) AS Test6,";

var split = splitQuery(query);
var output = document.getElementById("output")
for(var el in split){
  output.insertAdjacentHTML("beforeend",el + ": "+ split[el]+"<hr/>");
}

function splitQuery(input){
  var arr = [];
  var lastStart = 0;
  var open = 0;
  for(var i = 0, len = input.length; i < len; i++){
    var curr = input[i];
    if(curr === "("){open += 1;}
    else if(curr === ")"){ open = open < 1 ? 0 :open -=1;}
    else if(curr === ","){
      if(open === 0){
        arr.push(input.substring(lastStart,i));
        lastStart = i+1;
      }
    }else if(i+1 === len){
       arr.push(input.substring(lastStart,i+1));
    }
  }
  return arr;
}
&#13;
<div id="output"></div>
&#13;
&#13;
&#13;