用逗号分隔字符串但使用Javascript忽略双引号内的逗号

时间:2012-07-12 16:59:26

标签: javascript regex

我正在寻找[a, b, c, "d, e, f", g, h]变成6个元素的数组:a,b,c,“d,e,f”,g,h。我是RegEx的一个菜鸟,所以任何帮助都很棒。我试图通过Javascript来做到这一点。这就是我到目前为止所做的:

str = str.split(/,+|"[^"]+"/g); 

但是现在它正在拆分双引号中的所有内容,这是不正确的。 谢谢你的帮助。

编辑:好的抱歉,我的措辞非常糟糕。我被给了一个不是数组的字符串。

var str = 'a, b, c, "d, e, f", g, h';

我希望使用类似“拆分”功能的东西将 转换为数组。

17 个答案:

答案 0 :(得分:63)

这就是我要做的事。

var str = 'a, b, c, "d, e, f", g, h';
var arr = str.match(/(".*?"|[^",\s]+)(?=\s*,|\s*$)/g);
/* will match:

    (
        ".*?"       double quotes + anything but double quotes + double quotes
        |           OR
        [^",\s]+    1 or more characters excl. double quotes, comma or spaces of any kind
    )
    (?=             FOLLOWED BY
        \s*,        0 or more empty spaces and a comma
        |           OR
        \s*$        0 or more empty spaces and nothing else (end of string)
    )

*/
arr = arr || [];
// this will prevent JS from throwing an error in
// the below loop when there are no matches
for (var i = 0; i < arr.length; i++) console.log('arr['+i+'] =',arr[i]);

答案 1 :(得分:5)

这适合我。 (我使用分号,因此警报消息将显示将数组转换为字符串时添加的逗号与实际捕获的值之间的差异。)

var str = 'a; b; c; "d; e; f"; g; h; "i"';
var array = str.match(/("[^"]*")|[^;]+/g); 
alert(array);

答案 2 :(得分:3)

这是一个JavaScript函数:

function splitCSVButIgnoreCommasInDoublequotes(str) {  
    //split the str first  
    //then merge the elments between two double quotes  
    var delimiter = ',';  
    var quotes = '"';  
    var elements = str.split(delimiter);  
    var newElements = [];  
    for (var i = 0; i < elements.length; ++i) {  
        if (elements[i].indexOf(quotes) >= 0) {//the left double quotes is found  
            var indexOfRightQuotes = -1;  
            var tmp = elements[i];  
            //find the right double quotes  
            for (var j = i + 1; j < elements.length; ++j) {  
                if (elements[j].indexOf(quotes) >= 0) {  
                    indexOfRightQuotes = j; 
                    break;
                }  
            }  
            //found the right double quotes  
            //merge all the elements between double quotes  
            if (-1 != indexOfRightQuotes) {   
                for (var j = i + 1; j <= indexOfRightQuotes; ++j) {  
                    tmp = tmp + delimiter + elements[j];  
                }  
                newElements.push(tmp);  
                i = indexOfRightQuotes;  
            }  
            else { //right double quotes is not found  
                newElements.push(elements[i]);  
            }  
        }  
        else {//no left double quotes is found  
            newElements.push(elements[i]);  
        }  
    }  

    return newElements;  
}  

答案 3 :(得分:2)

我几乎喜欢被接受的答案,但是它不能正确解析空格,并且/或者没有对双引号进行修饰,所以这是我的功能:

    /**
     * Splits the given string into components, and returns the components array.
     * Each component must be separated by a comma.
     * If the component contains one or more comma(s), it must be wrapped with double quotes.
     * The double quote must not be used inside components (replace it with a special string like __double__quotes__ for instance, then transform it again into double quotes later...).
     *
     * https://stackoverflow.com/questions/11456850/split-a-string-by-commas-but-ignore-commas-within-double-quotes-using-javascript
     */
    function splitComponentsByComma(str){
        var ret = [];
        var arr = str.match(/(".*?"|[^",]+)(?=\s*,|\s*$)/g);
        for (let i in arr) {
            let element = arr[i];
            if ('"' === element[0]) {
                element = element.substr(1, element.length - 2);
            } else {
                element = arr[i].trim();
            }
            ret.push(element);
        }
        return ret;
    }
    console.log(splitComponentsByComma('Hello World, b, c, "d, e, f", c')); // [ 'Hello World', 'b', 'c', 'd, e, f', 'c' ]

答案 4 :(得分:1)

我知道它有点长,但这是我的看法:

var sample="[a, b, c, \"d, e, f\", g, h]";

var inQuotes = false, items = [], currentItem = '';

for(var i = 0; i < sample.length; i++) {
  if (sample[i] == '"') { 
    inQuotes = !inQuotes; 

    if (!inQuotes) {
      if (currentItem.length) items.push(currentItem);
      currentItem = '';
    }

    continue; 
  }

  if ((/^[\"\[\]\,\s]$/gi).test(sample[i]) && !inQuotes) {
    if (currentItem.length) items.push(currentItem);
    currentItem = '';
    continue;
  }

  currentItem += sample[i];
}

if (currentItem.length) items.push(currentItem);

console.log(items);

作为旁注,它可以在开始和结束时使用,也可以没有括号。

答案 5 :(得分:1)

这是一个非正则表达式,假设双引号将成对出现:

&#13;
&#13;
function splitCsv(str) {
  return str.split(',').reduce((accum,curr)=>{
    if(accum.isConcatting) {
      accum.soFar[accum.soFar.length-1] += ','+curr
    } else {
      accum.soFar.push(curr)
    }
    if(curr.split('"').length % 2 == 0) {
      accum.isConcatting= !accum.isConcatting
    }
    return accum;
  },{soFar:[],isConcatting:false}).soFar
}

console.log(splitCsv('asdf,"a,d",fdsa'),' should be ',['asdf','"a,d"','fdsa'])
console.log(splitCsv(',asdf,,fds,'),' should be ',['','asdf','','fds',''])
console.log(splitCsv('asdf,"a,,,d",fdsa'),' should be ',['asdf','"a,,,d"','fdsa'])
&#13;
&#13;
&#13;

答案 6 :(得分:0)

使用 npm 库 csv-string 来解析字符串而不是拆分:https://www.npmjs.com/package/csv-string

这将处理空条目

答案 7 :(得分:0)

const csvSplit = (line) => {
    let splitLine = [];

    var quotesplit = line.split('"');
    var lastindex = quotesplit.length - 1;
    // split evens removing outside quotes, push odds
    quotesplit.forEach((val, index) => {
        if (index % 2 === 0) {
            var firstchar = (index == 0) ? 0 : 1;
            var trimmed = (index == lastindex) 
                ? val.substring(firstchar)
                : val.slice(firstchar, -1);
            trimmed.split(",").forEach(v => splitLine.push(v));
        } else {
            splitLine.push(val);
        }
    });
    return splitLine;
}

只要引号始终位于包含需要排除的逗号的值的外部(即 csv 文件),此方法就有效。

如果你有像 '1,2,4"2,6",8' 这样的东西 它不会工作。

答案 8 :(得分:0)

我用一个简单的解析器解决了这个问题。

它只是简单地逐个字符遍历字符串,在找到 split_char(例如逗号)时拆分一个段,但还有一个开/关标志,通过查找 encapsulator_char(例如引号)来切换。它不需要封装器位于字段/段的开头(a,b","c,d 将产生 3 个段,其中 'b","c' 作为第二个),但它应该适用于带有转义封装字符的格式良好的 CSV。

function split_except_within(text, split_char, encapsulator_char, escape_char) {
    var start = 0
    var encapsulated = false
    var fields = []
    for (var c = 0; c < text.length; c++) {
        var char = text[c]
        if (char === split_char && ! encapsulated) {
            fields.push(text.substring(start, c))
            start = c+1
        }
        if (char === encapsulator_char && (c === 0 || text[c-1] !== escape_char) )             
            encapsulated = ! encapsulated
    }
    fields.push(text.substring(start))
    return fields
}

https://jsfiddle.net/7hty8Lvr/1/

答案 9 :(得分:0)

根据TYPESCRIPT解析任何CSV或CSV字符串代码

public parseCSV(content:string):any[string]{
        return content.split("\n").map(ar=>ar.split(/,(?=(?:(?:[^"]*"){2})*[^"]*$)/).map(refi=>refi.replace(/[\x00-\x08\x0E-\x1F\x7F-\uFFFF]/g, "").trim()));
    }

var str='"abc",jkl,1000,qwerty6000';

parseCSV(str);

输出:

[
"abc","jkl","1000","qwerty6000"
]

答案 10 :(得分:0)

这里是正则表达式we're using,用于从逗号分隔的参数列表中提取有效的参数,并支持双引号参数。它适用于概述的边缘情况。例如

  • 比赛中不包括引号
  • 在匹配项中使用空格
  • 使用空字段

(?<=")[^"]+?(?="(?:\s*?,|\s*?$))|(?<=(?:^|,)\s*?)(?:[^,"\s][^,"]*[^,"\s])|(?:[^,"\s])(?![^"]*?"(?:\s*?,|\s*?$))(?=\s*?(?:,|$))

证明:https://regex101.com/r/UL8kyy/3/tests

根据our guidelines,它避免了非捕获组和贪婪匹配。

我确信它可以简化,我愿意接受建议/其他测试用例。

对于感兴趣的任何人,第一部分都匹配双引号,以逗号分隔:

(?<=")[^"]+?(?="(?:\s*?,|\s*?$))

第二部分自己匹配以逗号分隔的参数:

(?<=(?:^|,)\s*?)(?:[^,"\s][^,"]*[^,"\s])|(?:[^,"\s])(?![^"]*?"(?:\s*?,|\s*?$))(?=\s*?(?:,|$))

答案 11 :(得分:0)

这一次将一个csv文件占用一行,并在语音标记内完整地吐出带有逗号的数组。如果没有检测到语音标记,则正常情况下只是.split(“,”)s ...可能会用某些东西替换第二个循环,但它照原样工作

function parse(str){
    if(str.indexOf("\"")>-1){
        var aInputSplit = str.split(",");
        var aOutput = [];
        //var adding = 0;
        for(i=0;i<aInputSplit.length;i++){
            if(aInputSplit[i].indexOf("\"")>-1){
                var sWithCommas = aInputSplit[i];
                for(z=i;z<aInputSplit.length;z++){
                    if(z != i && aInputSplit[z].indexOf("\"") == -1){
                        sWithCommas+= ","+aInputSplit[z];
                    }else if(z != i && aInputSplit[z].indexOf("\"") > -1){
                        sWithCommas+= ","+aInputSplit[z];
                        sWithCommas.replace(new RegExp("\"", 'g'), "");
                        aOutput.push(sWithCommas);
                        i=z;
                        z=aInputSplit.length+1;
                    }
                }
            }else{
                aOutput.push(aInputSplit[i]);
            }
        }
        return aOutput;
    }else{
        return str.split(",");
    }
}

答案 12 :(得分:0)

regex:/,(?=(?:(?:[^"]*"){2})*[^"]*$)/

const input_line = '"2C95699FFC68","201 S BOULEVARDRICHMOND, VA 23220","8299600062754882","2018-09-23"'

let my_split = input_line.split(/,(?=(?:(?:[^"]*"){2})*[^"]*$)/)[4]

Output: 
my_split[0]: "2C95699FFC68", 
my_split[1]: "201 S BOULEVARDRICHMOND, VA 23220", 
my_split[2]: "8299600062754882", 
my_split[3]: "2018-09-23"

请参考以下链接以获取说明:regexr.com/44u6o

答案 13 :(得分:0)

jsfiddle setting image code output image

如果输入字符串的格式为stringTocompare,则代码有效。 在https://jsfiddle.net/上运行代码以查看fiddlejs设置的输出。 请参阅屏幕截图。 您可以对其下面的代码使用拆分功能,并根据需要调整代码。 如果您不想在分割后附加逗号,请删除代码中的**中的粗体或单词attach = attach ** +&#34;,&#34; ** + actualString [t + 1]。

var stringTocompare='"Manufacturer","12345","6001","00",,"Calfe,eto,lin","Calfe,edin","4","20","10","07/01/2018","01/01/2006",,,,,,,,"03/31/2004"';

console.log(stringTocompare);

var actualString=stringTocompare.split(',');
console.log("Before");
for(var i=0;i<actualString.length;i++){
console.log(actualString[i]);
}
//var actualString=stringTocompare.split(/,(?=(?:(?:[^"]*"){2})*[^"]*$)/);
for(var i=0;i<actualString.length;i++){
var flag=0;
var x=actualString[i];
if(x!==null)
{
if(x[0]=='"' && x[x.length-1]!=='"'){
   var p=0;
   var t=i;
   var b=i;
   for(var k=i;k<actualString.length;k++){
   var y=actualString[k];
        if(y[y.length-1]!=='"'){        
        p++;
        }
        if(y[y.length-1]=='"'){

                flag=1;
        }
        if(flag==1)
        break;
   }
   var attach=actualString[t];
for(var s=p;s>0;s--){

  attach=attach+","+actualString[t+1];
  t++;
}
actualString[i]=attach;
actualString.splice(b+1,p);
}
}


}
console.log("After");
for(var i=0;i<actualString.length;i++){
console.log(actualString[i]);
}




  [1]: https://i.stack.imgur.com/3FcxM.png

答案 14 :(得分:0)

像堆栈这样的东西应该可以解决问题。在这里,我隐约地使用标记布尔值作为堆栈(只是用它来实现我的目的)。

var str = "a,b,c,blah\"d,=,f\"blah,\"g,h,";
var getAttributes = function(str){
  var result = [];
  var strBuf = '';
  var start = 0 ;
  var marker = false;
  for (var i = 0; i< str.length; i++){

    if (str[i] === '"'){
      marker = !marker;
    }
    if (str[i] === ',' && !marker){
      result.push(str.substr(start, i - start));
      start = i+1;
    }
  }
  if (start <= str.length){
    result.push(str.substr(start, i - start));
  }
  return result;
};

console.log(getAttributes(str));

答案 15 :(得分:-1)

我对此有类似的问题,而且我发现没有好的.net解决方案,所以去了DIY。注意:这也用于回复

Splitting comma separated string, ignore commas in quotes, but allow strings with one double quotation

但似乎在这里更适用(但在那里很有用)

在我的应用程序中,我正在解析csv,因此我的拆分凭证是&#34;,&#34;。我想这个方法只适用于你有一个char split参数的地方。

所以,我编写了一个忽略双引号内逗号的函数。它通过将输入字符串转换为字符数组并通过char

解析char来实现
public static string[] Splitter_IgnoreQuotes(string stringToSplit)
    {   
        char[] CharsOfData = stringToSplit.ToCharArray();
        //enter your expected array size here or alloc.
        string[] dataArray = new string[37];
        int arrayIndex = 0;
        bool DoubleQuotesJustSeen = false;          
        foreach (char theChar in CharsOfData)
        {
            //did we just see double quotes, and no command? dont split then. you could make ',' a variable for your split parameters I'm working with a csv.
            if ((theChar != ',' || DoubleQuotesJustSeen) && theChar != '"')
            {
                dataArray[arrayIndex] = dataArray[arrayIndex] + theChar;
            }
            else if (theChar == '"')
            {
                if (DoubleQuotesJustSeen)
                {
                    DoubleQuotesJustSeen = false;
                }
                else
                {
                    DoubleQuotesJustSeen = true;
                }
            }
            else if (theChar == ',' && !DoubleQuotesJustSeen)
            {
                arrayIndex++;
            }
        }
        return dataArray;
    }

对于我的应用程序,这个函数在任何输入中都会忽略(&#34;&#34;),因为这些不需要并存在于我的输入中。

答案 16 :(得分:-1)

假设您的字符串看起来真的像'[a, b, c, "d, e, f", g, h]',我相信这将是eval()的可接受用例:

myString = 'var myArr ' + myString;
eval(myString);

console.log(myArr); // will now be an array of elements: a, b, c, "d, e, f", g, h

修改:正如Rocket指出的那样,strict模式会移除eval将变量注入本地范围的能力,这意味着您需要这样做:

var myArr = eval(myString);