Разделите строку запятыми, но игнорируйте запятые в двойных кавычках, используя Javascript

Я ищу [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';

И я хочу превратить это в массив, используя что-то вроде функции split.

Ответ 1

Вот что я буду делать.

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

Ответ 2

Вот функция 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

Это хорошо работает для меня. (Я использовал точки с запятой, чтобы в предупреждающем сообщении была указана разница между добавленными запятыми при повороте массива в строку и фактические зафиксированные значения.)

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

Ответ 4

Здесь не-регулярное выражение, которое предполагает двойные кавычки, придет парами:

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

Ответ 5

регулярное выражение: /,(?=(?:(?:[^"]*"){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

Ответ 6

Я знаю это немного долго, но вот мое взятие:

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

В качестве побочного примечания он будет работать как с, так и без брекетов в начале и конце.

Ответ 7

Что-то вроде стека должно делать трюк. Здесь я смутно использую маркер boolean как стек (только чтобы моя цель служила с ним).

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

Ответ 8

настройка jsfiddle изображения код выходного изображения

Код работает, если ваша входная строка в формате stringTocompare. Запустите код на https://jsfiddle.net/, чтобы увидеть выходные данные для настройки fiddlejs. Пожалуйста, обратитесь к скриншоту. Вы можете использовать функцию split для одного и того же кода для кода ниже и настроить код в соответствии с вашими потребностями. Удалите жирный шрифт или слово с in ** из кода, если вы не хотите использовать запятую после разделения split attach = attach ** + "," ** +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

Ответ 9

Это берет CSV файл по одной строке за раз и выплевывает массив с запятыми внутри речевых меток без изменений. если речевые метки не обнаружены, это просто .split(",") s как обычно... может пробники заменить этот второй цикл чем-то, но он делает работу как есть

function parseCSVLine(str){
    if(str.indexOf("\"")>-1){
        var aInputSplit = str.split(",");
        var aOutput = [];
        var iMatch = 0;
        //var adding = 0;
        for(var i=0;i<aInputSplit.length;i++){
            if(aInputSplit[i].indexOf("\"")>-1){
                var sWithCommas = aInputSplit[i];
                for(var 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;
                        iMatch++;
                    }
                    if(z === aInputSplit.length-1){
                        if(iMatch === 0){
                            aOutput.push(aInputSplit[z]);
                        }                  
                        iMatch = 0;
                    }
                }
            }else{
                aOutput.push(aInputSplit[i]);
            }
        }
        return aOutput
    }else{
        return str.split(",")
    }
}

Ответ 10

Предполагая, что ваша строка действительно выглядит как '[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);

Ответ 11

У меня были схожие проблемы с этим, и я не нашел хорошего решения .net, поэтому пошел DIY. ПРИМЕЧАНИЕ. Это также использовалось для ответа на

Разделение разделенной запятой строки, игнорирование запятых в кавычках, но разрешить строки с одной двойной кавычкой

но здесь здесь более применимо (но полезно там)

В моем приложении я разбираю csv, поэтому мой разделительный учет - это ",". этот метод, я полагаю, работает только там, где у вас есть один аргумент разделения char.

Итак, я написал функцию, которая игнорирует запятые в двойных кавычках. он делает это путем преобразования входной строки в массив символов и разбора 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;
    }

Эта функция, к моему приложению, также игнорирует ("") на любом входе, поскольку они не нужны и присутствуют на моем входе.

Ответ 12

Здесь регулярное выражение, которое мы используем для извлечения допустимых аргументов из списка аргументов, разделенных запятыми, с поддержкой аргументов в двойных кавычках. Это работает для обозначенных крайних случаев. Например

  • не включает цитаты в матчах
  • работает с пробелами в спичках
  • работает с пустыми полями

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

Доказательство: https://regex101.com/r/UL8kyy/3/tests

Согласно нашим рекомендациям, это позволяет избежать групп захвата и жадного сопоставления.

Я уверен, что это может быть упрощено, я открыт для предложений/дополнительных тестовых случаев.

Для всех, кто заинтересован, первая часть соответствует аргументам, заключенным в двойные кавычки, разделенные запятыми:

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

А вторая часть соответствует аргументам, разделенным запятыми:

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